一些涉及类析构函数和删除运算符的内存管理问题?

时间:2011-07-06 17:03:47

标签: c++ memory-management destructor

在阅读了一些教程之后,我仍然不清楚有关C ++内存管理的一些观点。

1。 当使用new运算符声明的类超出范围时,它的析构函数被调用并释放内存吗? 是否有必要调用delete运算符来释放类的内存并将其析构函数调用为?

class Test{};

void newTest(){
    Test *t = new Test;
}

int main()
{
    newTest();
    return 0;
}

2。 使用new关键字声明的变量(例如向量)是否会在它们所在的类被销毁时释放? 是否必须在类的析构函数中显式删除这些变量?

class Test{
    vector<int> *vec;
public:
    Test();
};

Test::Test(){
    *vec = new vector<int>;
}

void newTest(){
    Test t;
}

int main()
{
    newTest();
    return 0;
}

3。 与问题2相同,但在堆栈上声明了常规变量。 在下面的例子中,当t超出范围时,是否删除了向量vec?

class Test{
    vector<int> vec;
};

void newTest(){
    Test t;
}

int main()
{
    newTest();
    return 0;
}

4。 最后,这是在类中声明向量的更好方法,通常(在堆栈上)或使用new关键字(在堆上)?

6 个答案:

答案 0 :(得分:2)

听起来你可能来自Java背景,因此new的内容在C ++中的工作方式略有不同。

  1. 必须使用new明确销毁分配有delete的内存。此示例有内存泄漏。

  2. 与问题1类似,您必须删除类析构函数中的内存以回收它。

  3. 在这种情况下,矢量将被自动销毁。

  4. 在一个班级中,总是喜欢按价值存储成员(而不是新的),除非你有特殊的理由不这样做。仅仅因为它存储在类中的值并不意味着它存在于堆栈中,它与包含类占用的内存区域相同。

  5. 最后请注意,在C ++中,您可以使用RAII使内存管理更不容易出错。例如,查看shared_ptr,scoped_ptr和unique_ptr。这些都会在适当的时候自动释放new分配的内存。

答案 1 :(得分:1)

  1. 不,不会调用析构函数,也不会释放内存。你必须delete对象。
  2. 不,变量未被释放。你必须在析构函数中删除它们。
  3. 是的,删除了vec(调用析构函数并释放内存)。
  4. 通常在堆栈上更好,如果可能的话。例如,如果将对象的所有权传递给另一个对象,则可能无法实现。另外,不应该在堆栈上分配太多内存(操作系统对此有限制),在这种情况下,应该在堆上分配对象。

答案 2 :(得分:1)

  1. 不,当指针超出范围时,使用new创建的对象不会自动销毁。您需要明确delete任何此类对象。
  2. 答案相同。必须明确释放分配有new的任何内存。大多数编写良好的类将在析构函数中为您执行此操作。如果您正在编写该类,请确保清理该类使用的任何内存。
  3. 此对象会自动销毁。并且,如果编写得好,它将自动销毁它分配的任何内存。
  4. 大多数类实例应该作为局部变量分配,因为这样可以确保为您自动清理它们。但是,如果您需要全局或作为课程的一部分,您需要适当地声明它们。

答案 3 :(得分:1)

  
      
  1. 当使用new运算符声明的类超出范围时,它的析构函数被调用并释放内存吗?是否有必要调用delete运算符来释放类的内存并将其析构函数调用为?
  2.   

首先是一些术语:

变量是对象或指针(没有使用新指针声明clas) 当对象超出范围时,对象会自动销毁 指针 NOT 会自动删除。

第二个更喜欢obejcts指针

void newTest()
{
    Test t;  // t created here and automatically destroyed.
}

第三。如果必须创建指针。把它放在智能指针内。

void newTest()
{
    std::auto_ptr<Test> t(new Test());  // t created here and automatically destroyed.
                                        // Which will call delete on the contained pointer.
}

回答问题1:

您声明的指针超出范围,但内存是析构函数未被调用且内存泄漏。您需要手动完成(或使用我指出的技术之一)。

  
      
  1. 使用new关键字声明的变量(例如向量)是否会在其所在的类被销毁时释放?是否必须在类的析构函数中明确删除这些变量?
  2.   

术语

您的意思是pointers initialized with new,而不是declared with the new keyword

回答问题2。

没有。您必须在析构函数中手动调用destroy。但最好不要在课堂上有指针。而是在类中声明一个矢量对象,然后它将被自动销毁。

class Test
{
    vector<int>                   vectorObject;
    std::auto_ptr<vector<int> >   vectorPtrInSmartPointer;
    vector<int>*                  vectorRaw
public:
    Test();
    ~Test();
private:
    Test(Test const& copy);
    Test& operator=(Test const& copy);
};

Test::Test()
   : vectorPtrInSmartPointer(new vector<int>())  // Need to initialize the smart pointer.
   , vectorRaw(new vector<int>)                  // Need to initialize the RAW pointer
{
   // Note the vectorObject was automatically created.
}
Test::~Test()
{
   delete vectorRaw;                             // Need to manually release the RAW pointer.
}
// Smart pointer and object auto released.

注意:     因为类Test包含RAW指针(vector *),所以我必须手动禁用复制构造函数Test::Test(Test const&)和赋值运算符Test& operator=(Test const&)。这是为了确保遵循规则3。

  
      
  1. 与问题2相同,但在堆栈上声明了常规变量。在以下示例中,当t超出范围时,是否删除了向量vec?
  2.   

  
      
  1. 最后,哪个是在类中声明向量的更好方法,通常(在堆栈上)或使用new关键字(在堆上)?
  2.   

调用堆栈/堆会掩盖细节(因为成员可能是动态分配对象的自动成员)。更喜欢将它们视为automatic variablesdynamic variables。当它们的包含范围被销毁时,automatic variables会被自动销毁。因此,对于函数变量,这意味着当您离开函数时。对于类成员,这意味着对象被销毁。选择是优先使用automatic variables(即不用新分配)。

答案 4 :(得分:0)

这两个简单的规则应该回答所有问题:

  1. 您的代码中的delete应与new一样多。
  2. 首选,尽可能从堆栈中分配堆栈。

答案 5 :(得分:0)

您应该更喜欢说对象具有动态存储而不是“在堆上”。同样,使用“自动存储”而不是“在堆栈上”。

前者实际上用于标准,而后者更通俗。

如果对象具有自动存储,则当对象超出范围时(在包含块的末尾),编译器将自动调用其析构函数。

需要明确释放分配有new的内存。将回收实际指针的存储空间,但不会回收它指向的对象。

因此,如果您使用new,则需要匹配deletenew[]需要与delete[]匹配。

(“智能指针”非常有用,因为它有助于减轻您跟踪newdelete的问题。查找它!)。

销毁一个向量(如果使用new分配,则通过删除,或者如果自动将其保留为范围)将调用其元素的析构函数。这就是为什么我们应该成为持有多个对象的首选方式。

结论:

如果可能,尝试使用智能指针或集合。 否则,请确保delete new。 (如果你编写一个类,在构造函数中分配任何动态成员并在类'析构函数中删除它们。)