析构函数和 delete(),哪个先出现的?C++

6

这个网站上有很多回答都提到delete()会调用析构函数。但下面示例代码中似乎在析构函数中调用了delete(),那么当对象在堆栈和堆中初始化时,delete()的正确使用方法是什么呢?

点击查看来源。

#include <iostream>
using namespace std;
 
class SmartPtr {
    int* ptr; // Actual pointer
public:
    // Constructor: Refer https:// www.geeksforgeeks.org/g-fact-93/
    // for use of explicit keyword
    explicit SmartPtr(int* p = NULL) { ptr = p; }
 
    // Destructor
    ~SmartPtr() { delete (ptr); }
 
    // Overloading dereferencing operator
    int& operator*() { return *ptr; }
};
 
int main()
{
    SmartPtr ptr(new int());
    *ptr = 20;
    cout << *ptr;
 
    // We don't need to call delete ptr: when the object
    // ptr goes out of scope, the destructor for it is automatically
    // called and destructor does delete ptr.
 
    return 0;
}

7
你的困惑来自于这个程序涉及到两个对象:SmartPtr 和它所管理内存中的 int~SmartPtr() 调用 delete 来删除 int 对象,而不是它自己。 - YSC
3
@user207421,感到困惑是普遍人权,不应由您决定谁会被什么事情困扰;) - YSC
1
对于原始指针,没有任何自动化。指针可以指向不属于包含类的对象(或成员或对象的元素)。因此,在析构函数中删除指针是由程序逻辑需要的,即SmartPtr拥有该int,而编译器并不知道这一点。 - Öö Tiib
1
@Xfce4 简而言之,不行。如果你在析构函数中没有执行delete ptr,那么指向ptr的对象将永远不会被销毁。与其他(垃圾回收)语言不同,在C++中没有隐式清理动态分配的对象。简单来说,如果你从析构函数中删除了delete ptr,则该代码中的对象(类型为int)将被泄漏(没有指针指向它,因此程序中的任何代码都无法找到该对象,如果程序无法找到该对象,则程序无法销毁它)。 - Peter
1
对于真实的代码(而非所提供的简化示例 - 感谢提供),您需要处理复制构造函数和复制赋值运算符,并可能还要提供移动构造函数和移动赋值运算符。 - Eljay
显示剩余10条评论
1个回答

9

当析构函数SmartPtr获得控制权时

 ~SmartPtr() { delete (ptr); }

执行其主体。在主体中使用了运算符delete进行执行。如果指针ptr指向的是一个类类型的对象,则在释放对象的动态分配内存之前,该类的析构函数将被依次调用。

这里是一个演示程序。

#include <iostream>

int main()
{
    struct A
    {
        ~A() { std::cout << "A::~A() called\n"; }
    };

    struct B
    {
        B() : ptr( new A ) {};
        ~B()
        {
            std::cout << "B::~B() called\n";
            delete ptr;
        }
        A *ptr;
    };

    { 
        B b; 
    }

    std::cout << "That is all!\n";
}

程序输出为:

B::~B() called
A::~A() called
That is all!

如果在类B的析构函数内删除此语句

delete ptr;

如果类B的对象不被销毁,那么类A动态分配的对象将会产生内存泄漏,它们占用的内存也不会被释放。


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