提问者:小点点

当一个新对象被分配到它的地址时,对象必须被销毁吗?


请考虑以下代码。

#include <stdio.h>
using namespace std;

constexpr size_t TOTAL = 2;

class thing
{
private:
    inline static size_t NEXT_ID = 0;
    size_t id;

public:
    thing() : id(NEXT_ID++)
    {
        printf("Thing %zd created.\n", this->id);
    }
    ~thing()
    {
        printf("Thing %zd destroyed.\n", this->id);
    }
};

class container
{
private:
    inline static size_t NEXT_ID = 0;
    size_t id;
    thing* things;

public:
    container() : id(NEXT_ID++)
    {
        this->things = new thing[TOTAL];
        printf("Container %zd created.\n", this->id);
    }
    ~container()
    {
        delete[] this->things;
        printf("Container %zd destroyed.\n", this->id);
    }

    thing& at(size_t idx)    // this is the important method
    {
        return this->things[idx];
    }
};

int main()
{
    container c;
    c.at(0) = thing();   // here is the problem
    return 0;
}

输出是我没想到的。

Thing 0 created.
Thing 1 created.
Container 0 created.
Thing 2 created.
Thing 2 destroyed.
Thing 1 destroyed.
Thing 2 destroyed.
Container 0 destroyed.

我知道东西2是一个临时对象,所以它被破坏了两次。 我有几个问题是关于事物0发生了什么。

  • 为什么东西0没有被销毁?
  • 是否会发生内存泄漏?
  • 我是否必须以某种方式销毁内容0,或者它是否已被成功覆盖?

共2个答案

匿名用户

在本声明中

c.at(0) = thing();

使用由编译器复制赋值运算符隐式定义的。 因此表达式C.at(0)引用的对象的数据成员id将等于表达式Thing()创建的临时对象的id,该临时对象的id等于2

在此语句中,临时对象被创建,并在结束时被销毁

Thing 2 created.
Thing 2 destroyed.

现在对象c包含两个子对象thing,它们存储为数组的元素。 子对象的id为21

删除它们的顺序与创建它们的顺序相反

Thing 1 destroyed.
Thing 2 destroyed.  // previously it has id equal to 0

因此程序不存在内存泄漏。 从程序输出中可以看到,所有创建的对象都已成功删除。

匿名用户

没有对同一对象的析构函数的双重调用。 问题只是出在你的输出上。 您正在打印ID,但C.at(0)=thing();中的复制分配将ID从临时对象复制到容器中的对象。 这就是你看到两个“东西2被摧毁”的原因。 也没有“东西被破坏”。

如果您想要更好的日志记录机制,可以打印this指针。 对象的地址在对象的生存期内不会改变,它是对象的唯一标识符。 当然,为了方便起见,您还可以另外打印id

printf("Thing %p %zd created.\n", static_cast<void>(this), this->id);
printf("Thing %p %zd destroyed.\n", static_cast<void>(this), this->id);

这样可以得到如下输出(当然,0x11111111,0x22222222和0x33333333在您的情况下看起来会有所不同):

已创建事件0x11111111 0.
事件0x22222222 1已创建。
容器0已创建。
事件0x33333333 2已创建。
事件0x33333333 2已销毁。
事件0x22222222 1已销毁。
事件0x11111111 2已销毁。
容器0已销毁。