当一个新对象分配给它的地址时,对象是否必须被销毁?
Does object have to be destroyed when a new object is assigned to its address?
考虑以下代码。
#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.
我知道 Thing 2
是一个临时对象,这就是它被销毁两次的原因。我有几个关于 Thing 0
.
的问题
- 为什么
Thing 0
没有被摧毁?
- 会不会有内存泄漏?
- 我必须以某种方式销毁
Thing 0
还是它被成功覆盖了?
在此声明中
c.at(0) = thing();
这里使用了编译器拷贝赋值运算符隐式定义的。因此表达式 c.at(0)
引用的对象的数据成员 id
等于表达式 thing()
创建的临时对象的 id 等于 2
.
在这个语句中创建临时对象并在最后销毁
Thing 2 created.
Thing 2 destroyed.
现在对象 c
包含两个子对象 thing
存储为数组的元素。子对象有 id(s) 2
和 1
.
它们的删除顺序与创建顺序相反
Thing 1 destroyed.
Thing 2 destroyed. // previously it has id equal to 0
所以程序没有内存泄漏。从程序输出中可以看出,所有创建的对象都已成功删除。
没有对同一对象的析构函数进行两次调用。问题仅出在您的输出中。您正在打印 id
但 c.at(0) = thing();
中的复制分配将 id
从临时对象复制到容器中的对象。这就是您看到两个“Thing 2 destroyed”的原因。并且没有“Thing 0 destroyed”。
如果你想要更好的日志记录机制,你可以打印 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 在你的情况下看起来会有所不同):
Thing 0x11111111 0 created.
Thing 0x22222222 1 created.
Container 0 created.
Thing 0x33333333 2 created.
Thing 0x33333333 2 destroyed.
Thing 0x22222222 1 destroyed.
Thing 0x11111111 2 destroyed.
Container 0 destroyed.
考虑以下代码。
#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.
我知道 Thing 2
是一个临时对象,这就是它被销毁两次的原因。我有几个关于 Thing 0
.
- 为什么
Thing 0
没有被摧毁? - 会不会有内存泄漏?
- 我必须以某种方式销毁
Thing 0
还是它被成功覆盖了?
在此声明中
c.at(0) = thing();
这里使用了编译器拷贝赋值运算符隐式定义的。因此表达式 c.at(0)
引用的对象的数据成员 id
等于表达式 thing()
创建的临时对象的 id 等于 2
.
在这个语句中创建临时对象并在最后销毁
Thing 2 created.
Thing 2 destroyed.
现在对象 c
包含两个子对象 thing
存储为数组的元素。子对象有 id(s) 2
和 1
.
它们的删除顺序与创建顺序相反
Thing 1 destroyed.
Thing 2 destroyed. // previously it has id equal to 0
所以程序没有内存泄漏。从程序输出中可以看出,所有创建的对象都已成功删除。
没有对同一对象的析构函数进行两次调用。问题仅出在您的输出中。您正在打印 id
但 c.at(0) = thing();
中的复制分配将 id
从临时对象复制到容器中的对象。这就是您看到两个“Thing 2 destroyed”的原因。并且没有“Thing 0 destroyed”。
如果你想要更好的日志记录机制,你可以打印 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 在你的情况下看起来会有所不同):
Thing 0x11111111 0 created.
Thing 0x22222222 1 created.
Container 0 created.
Thing 0x33333333 2 created.
Thing 0x33333333 2 destroyed.
Thing 0x22222222 1 destroyed.
Thing 0x11111111 2 destroyed.
Container 0 destroyed.