在析构函数中调用“delete”运算符时出现编译器错误“编译器堆空间不足”

Posted

技术标签:

【中文标题】在析构函数中调用“delete”运算符时出现编译器错误“编译器堆空间不足”【英文标题】:Compiler error "compiler is out of heap space" when calling `delete` operator in the destructor 【发布时间】:2018-06-29 14:40:46 【问题描述】:

我写了一个名为“TreeContainer”的类。我的目标是设计一个树容器,将内容保存在树状层次结构中。每个树容器都应该像文件系统中的文件夹/目录一样工作。一个文件夹(树)可以有子文件夹(子树)和其他文件(子项)。

我将它包含在另一个源文件中,说它的名称是“TreeUser.cpp”。当我尝试调试/运行我的项目时,Visual Studio 会一一编译项目源文件,我会在 IDE 的“输出”面板中查看当前正在编译的文件。当涉及到 TreeUser.cpp 文件时,它花费了太多时间。最后给出下面的致命错误,编译停止。

错误 C1060 编译器堆空间不足 [此处为项目名称] [Visual Studio 安装路径]\visual studio\vc\tools\msvc\14.14.26428\include\xmemory0 962

类的代码如下。

TreeContainer.cpp

#pragma once

#include <vector>

template <class T>
class TreeContainer

    public:
        using SubTreeContainerType = std::vector<TreeContainer<T *> *>;
        using SubItemContainerType = std::vector<T *>;

        TreeContainer();
        ~TreeContainer();

        // ... (Lots of member functions here. Removing or keeping them has no effect.)

    private:
        SubTreeContainerType SubTrees;
        SubItemContainerType SubItems;

;

template <class T>
TreeContainer<T>::TreeContainer()
    : SubTrees(), SubItems()



template <class T>
TreeContainer<T>::~TreeContainer()

    for (typename SubTreeContainerType::iterator it=SubTrees.begin(); it!=SubTrees.end(); ++it)
    
        //delete *it; (I get the error when I uncomment this line.)
    
    for (typename SubItemContainerType::iterator it=SubItems.begin(); it!=SubItems.end(); ++it)
    
        delete *it;
    

经过多次试验,我发现析构函数中的行导致了问题。删除它可以解决问题。但我需要那条线来清理内存。

在该行中,我在容器SubTrees 的内容上调用delete 运算符。它应该递归地调用每个子树上的析构函数。我在这里做错了什么还是这是 Visual Studio 中的错误。

IDE 版本:Visual Studio Community 2017 15.7.4

命令行选项:

/permissive- /GS /W3 /wd"4290" /wd"5040" /Zc:wchar_t /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc141.pdb" /Zc:inline /fp :precise /D "SC_DEBUG" /D "_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /std:c++17 /FC /Fa "x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\Project Name.pch" /diagnostics:classic

【问题讨论】:

如果这些容器是用来拥有相关对象的,那么您真的应该使用std::unique_ptr&lt;T&gt;,而不是T*。这样至少,你不需要为这个对象滚动你自己的析构函数。即使std::unique_ptr 不适合您的任务,您仍然应该重组代码以遵守适当的 RAII 约定,而不是让单个对象直接负责多个资源的生命周期,并且而是将每个资源的职责委托给它自己的对象。 【参考方案1】:

看起来您从模板创建了无限多个类,因为TreeContainer&lt;T&gt; 中的SubTreeContainerType 引用了TreeContainer&lt;T *&gt;T 指针的容器)。

而析构函数需要子树向量的析构函数,子树又需要TreeContainer&lt;T *&gt;的析构函数,又需要TreeContainer&lt;T **&gt;的析构函数等pp。

解决方案:

using SubTreeContainerType = std::vector<TreeContainer<T> *>;

或者,如果您真的希望子树容器引用指向 T 的指针,请在实现方法之前为中断递归的指针添加模板特化。

【讨论】:

以上是关于在析构函数中调用“delete”运算符时出现编译器错误“编译器堆空间不足”的主要内容,如果未能解决你的问题,请参考以下文章

如果debug调试的时候中断总是停在析构函数的delete[] p上

即使内存不是动态分配的,在析构函数中是不是需要`delete ptr;`? [复制]

检查指针在析构函数中不为空[重复]

重载类的new和delete运算符成员函数

为啥我必须在析构函数中调用 MPI.Finalize() ?

glDeleteBuffers() 在析构函数调用期间崩溃