4

我在我的代码中使用了额外的括号。我认为在局部变量范围结束后应该调用析构函数,但它不像这样工作:

class TestClass {
public:
    TestClass() {
        printf( "TestClass()\n" );
    }
    ~TestClass() {
        printf( "~TestClass()\n" );
    }
};

int main() {
    int a, b, c;
    {
         TestClass *test = new TestClass();
    }
}

它输出:

测试类()

所以它没有调用 TestClass 的析构函数,但为什么呢?如果我手动调用它(删除测试),它会调用析构函数,对。但是为什么它在第一种情况下不调用析构函数呢?

4

3 回答 3

14
TestClass *test = new TestClass();

您使用newwhich 创建一个动态分配的对象(很可能放置在堆上)。此类资源需要您手动管理。通过管理,您应该delete在使用它之后使用它。

{
     TestClass *test = new TestClass();
     // do something
     delete test;
}

但是对于您的大多数目的和意图,您只需要使用自动存储对象,这样您就不必手动管理对象了。它也很可能具有更好的性能,尤其是在短期对象中。除非您有充分的理由不这样做,否则您应该始终更喜欢使用它们。

{
     TestClass test;
     // do something
}

但是,如果您需要动态分配对象或指针的语义,最好使用某种机制为您封装对象/资源的删除/释放,这也为您提供额外的安全性,尤其是在您使用时异常和条件分支。在您的情况下,最好使用std::unique_ptr.

{
     std::unique_ptr<TestClass> test(new TestClass());
     // auto test = std::make_unique<TestClass>();  in C++14

     // do something (maybe you want to pass ownership of the pointer)
}


以下是帮助您决定是使用自动存储对象还是动态分配对象的相关链接:为什么 C++ 程序员应尽量减少“new”的使用?

于 2013-08-07T07:46:40.233 回答
8

因为您有一个指向动态分配对象的指针。只有指针超出范围,而不是它指向的对象。您必须调用delete指针才能调用指针的析构函数。

尝试使用自动存储对象:

{
  TestClass test;
}

在这里,析构函数在退出作用域时被调用。

不鼓励在 C++ 中使用指向动态分配对象的原始指针,因为它很容易导致资源泄漏,就像代码示例中显示的那样。如果确实需要指向动态分配对象的指针,明智的做法是使用智能指针处理它们,而不是尝试手动处理它们的销毁。

于 2013-08-07T07:44:51.007 回答
3

这个答案已经足够好了,但只是补充一些。

我看到你已经被编码了Java。不需要在堆栈关键字中创建C++变量/对象。new实际上,当您使用关键字时,new您的对象是在堆中创建的,并且在离开范围后不会破坏。要摧毁它,你需要打电话给delete你的案子delete test;

在像您这样的结构中,离开作用域后,您只会丢失指向对象的指针,因此在离开作用域后,您将无法释放内存并调用析构函数,但最终操作系统会在exit()指令执行后调用析构函数。

总结一下C++!=Java

于 2013-08-07T10:27:11.013 回答