离开作用域时没有调用析构函数

Destructor not being called when leaving scope

本文关键字:调用 析构函数 作用域 离开      更新时间:2023-10-16

我正在学习c++中的内存管理,我不明白为什么只有一些析构函数在离开作用域时被调用。在下面的代码中,myfunc结束时只调用obj1析构函数,而不调用动态分配的obj2。

int myfunc (cl1 *oarg) {
    cout << "myfunc called" << std::endl;
    cl1 obj1(222,"NY");
    cl1 *obj2;
    obj2= new cl1;
    oarg->disp();
    obj2 -> ~cl1 ;
}

这是我的析构函数:

cl1 :: ~cl1 () {
std::cout<< " cl1 destructor called"<<std::endl;
std::cout << this->data << std::endl; //just to identify the obj
delete [] str;
str = NULL ;
};

如果您使用new分配对象

obj2= new cl1;

那么除非在它上面调用delete,否则它的析构函数不会被隐式调用。

编辑:正如@David在注释中所说,可以显式地调用对象的析构函数,但根据我的经验,很少需要手动调用析构函数,除非使用放置new的新版本。

堆栈上的变量在作用域结束时被隐式清理(通过调用它们的析构函数)。

动态分配的对象不会被隐式清理,它是用户调用delete显式清理它们的责任。

这就是不应该使用原始指针而应该使用智能指针的原因。

动态分配的对象是你的责任 -你需要显式地清理它们。自动对象(如obj1)在退出作用域时被清理,自动。在这种情况下,在退出作用域之前显式调用delete obj2。注意:obj2 -> ~cl1一行不做任何事情——delete将负责正确触发析构函数。

obj1cl1类型的对象,具有自动存储持续时间(它在堆栈上分配,其生存期由其所在的作用域决定)

obj1cl1*类型的对象。也就是说,它是一个指针。指针也具有自动存储持续时间,但它所指向的对象没有。它指向自由存储区中动态分配的对象。

当您离开作用域时,具有自动存储持续时间的对象将被销毁。obj1被销毁,调用析构函数。obj2也被销毁,但是obj2不是cl1类型的,所以它不调用cl1的析构函数。它是一个指针,当它被销毁时,它不会做任何特别的事情。

指针不拥有它们所指向的对象,因此它们不做任何事情来确保所指向的对象被销毁或清理。(如果你想要一个"拥有"的指针,这就是智能指针类的作用)

考虑你可以很容易地有多个指针指向同一个对象。

如果指针自动删除它所指向的对象,则会导致错误。两个不同指针所指向的对象会被删除两次。

obj2 -> ~cl1 ;

不要这样做!用delete obj2;代替。

附录
你要做的是显式地调用析构函数。您的代码不会这样做。您的代码正在获取析构函数的地址,然后将其放入位桶中。你的代码是无操作的。显式调用析构函数的正确方法是obj2->~cli();

显式调用析构函数通常是不应该做的。

你应该做的是删除由new创建的内存。正确的方法是使用delete操作符。这会自动调用析构函数,并且释放内存。析构函数不释放内存。未使用delete导致内存泄漏。

当在堆栈上创建的对象超出作用域时,将自动调用析构函数。

对于动态分配的对象,需要调用delete obj。Delete会自动为你调用析构函数。

对于动态分配的对象应该使用delete:

delete obj2;

this调用析构函数并释放内存。你最好使用智能指针来管理这些对象——即使在newdelete之间抛出异常的情况下,它们也会为你调用delete

首先,您应该使用delete操作符来销毁对象,而不是直接调用其析构函数。其次,通过做new,你告诉编译器,你想要删除对象时,它超出了作用域。在这种情况下,您需要显式地使用delete objj2;来删除对象。

使用std::unique_ptr或std::shared_ptr代替原始指针。这是避免内存泄漏或双重释放的最好方法。

这在现代c++中是正确的。

int myfunc (cl1 *oarg) 
{
    cout << "myfunc called" << std::endl;
    cl1 obj1(222,"NY");
    std::unique_ptr<cl1> obj2( new cl1 );
    oarg->disp();
}