如何在我的类析构函数中释放内存?

3

好的,我想这个问题可能听起来太傻了,但是内存管理(特别是在C/C++中)从来不是我的强项,而且由于它通常不是很显著,我倾向于忽略它。如果所有这些听起来都很愚蠢,请原谅我。然而,由于我的当前项目涉及大量数据和处理,内存消耗轻松地在几秒钟内就超过了2GB,这肯定会减慢整个过程,所以...是时候开始考虑如何解决它了。


因此,这是我的情况...

我的主要类(我正在创建数百万个实例(希望自动删除,因为它们停止使用),所以应该是罪魁祸首)大致上是这样的:

class MyClass
{
    public:
        // My Constructors
        MyClass ();
        MyClass (std::string param);

        // My Destructor (still empty)
        virtual ~MyClass ();

        // Some methods
        void methodA(std::string moves);
        void methodB();

        //----------------------
        // My Variables
        //----------------------
        boost::array<int,64> arrA;
        boost::array<unsigned int,13> arrB;
        unsigned int key;

        boost::array<int,3> arrC;       
        int argA;
        int argB;
};

以下是创建上述类的实例的大致方式(实际代码已被修改):

vector<MyClass*> SomeOtherClass::getListOfObjects()
{   
    vector<MyClass*> objects;

    for (int i=0; i<MAX_OBJS; i++)
    {
          // Do some preparatory work
          objects += new MyClass();
    }

    return objects;
}

以下是上述函数的结果如何使用的示例:

以下是上述函数的结果如何使用的示例:

void SomeOtherClass::doSth()
{
    vector<MyClass*> objs = this->getListOfObjects();
    int objsSize = objs.size();

    for (int i=0; i<objsSize; i++)
    {
        MyClass* obj = objs[i];

        // Do sth with obj

        delete objs[i];
    }
}

所以,我的问题是:

  • 在析构函数中,我应该做些什么,以便当对象不再需要并因此被释放时,它的所有“子组件”也会被释放?(例如2个boost::array

  • 您是否注意到上述方法有任何问题?


如果您对我的实现还有其他需要了解的内容,请告诉我...


3
“通常这不是一个显而易见的事情,我倾向于忽视它。”-- 最糟糕的态度。你是否熟悉“delete”关键字? - Jonathon Reinhart
你缺少了复制/移动构造函数。 - BЈовић
1
你的类中没有需要管理的内存。你创建了多少个MyClass对象? - Jesse Good
2
@Dr.Kameleon:我认为目前的硬件上没有任何当前的内存分配器能够达到那样的速度。更不用说这个对象至少有336字节,所以1亿个对象将占用33.6GB的内存,而这在今天的普通计算机上是无法容纳的。 - Jan Hudec
1
你可能不需要一个指针向量(使用vector<MyClass>代替),只需小心,因为它需要更多的复制(将其作为引用传递给getListOfObjects而不是返回它,在任何情况下这都是一个好主意)。 - Bernhard Barker
显示剩余13条评论
4个回答

6
您的类成员看起来并没有动态分配,因此您不需要在析构函数中显式地 delete 任何内容。如果您偶然忘记释放一些在此问题中使用 new 分配的内存指针,则需要在析构函数中 delete 这些指针。
请记住,如果您使用 new,则需要使用 delete,同样适用于 new[] - delete[]。除了分配给 std::unique_ptr 的情况之外。
如果您的 MyClass 对象本身是使用 new 在堆上分配的,则必须对它们进行 delete
附言:如果您正在使用 C++11,则现在应该使用 std::array
从您的新代码中可以明显看出,谁保留了从 getListOfObjects() 返回的列表,需要在销毁时调用 delete 来删除每个元素。这很可能是 SomeOtherClass 的析构函数。
或者,您可以使用 std::unique_ptrstd::shared_ptr(或任何可能相关的 boost 智能指针)包装 MyClass* 指针,这样当持有它们的向量超出范围并被销毁时,它们将自动删除。
如果 doSth 在其表示中是准确的,并确保所有 MyClass 实例都得到了 delete,则从内存泄漏的角度来看,此代码似乎很好。

1
我假设您能够判断它们是动态分配的,因为类成员将会是指针,对吗? - johnbakers
@SebbyJohanns 是的,那是我正在使用的...让我添加一个警告。 - Karthik T
1
@SebbyJohanns 指针数据成员并不意味着动态分配。您必须检查这些指针是否指向使用 newnew[] 动态分配的某些内存。即使是这样,也不完全清楚谁有责任调用 delete。在这些情况下最好避免使用原始指针,并使用适当的智能指针。 - juanchopanza
2
@Dr.Kameleon,您可能需要编辑问题以显示分配和释放对象的代码以及向量的定义,并在那里添加这些细节。 - Karthik T
@juanchopanza 没有指针已经足够推断析构函数是自由的。 - Karthik T
显示剩余5条评论

3
我看到的是一个正确管理内存的类。 boost::array 是对普通数组的精美包装(boost::array<int,64> arrA 就是带有添加方法的 int arrA[64],以便将其用作标准库算法的随机访问只读集合),因此它作为对象的一部分分配。

现在,如果你说你有一个泄漏,你显然会在某处错误地管理内存,但不是在这里。


在现代C++中,趋势是避免自己编写删除代码,而是交给专门的析构函数处理。鉴于上述分配代码,Boost.Pointer Container 可能是正确的工具。


1
我看到的都是在堆栈上分配的,所以它们被正确管理并在析构函数中很好地删除。如果有内存泄漏,可能是因为您调用了new MyClass但没有释放它们,或者其他地方出了问题。
我在编辑后的代码中看到一个向量,您是否正在删除由SomeOtherClass::getListOfObjects返回的objects项?
此外,您可以使用boost::shared_ptr<MyClass>而不是原始指针MyClass*

“我看到的都是在堆栈上分配的” - 这并不正确...成员将嵌入在对象创建的位置,这可以是静态的、在堆栈上或在堆上。关键点是无论应用于对象的内存管理是什么,都会自动处理成员...这就是你正确警告 new Myclass 无释放的地方。 - Tony Delroy

1
这听起来有点奇怪。
我的主要类(我正在创建数百万个实例(希望它们会自动删除,因为它们不再使用)。
如果您正在创建 MyClass 的实例,并且没有使用某种智能指针进行创建,则它们不会自动删除,您需要完成这项工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接