所以我在C ++中阅读了一段文本并遇到了以下代码:
class example
{
int dataMember;
public:
example& assign(const example& source)
{
if(this!=&source)
{
this->~example();
new (this) example(source);
}
}
};
好的,所以我试图解码这个函数分配正在做什么。我的理解还是:
该函数对类的实例进行常量引用,并返回对该类的引用。
在if
块内,首先为当前实例调用析构函数(据我所知,当前对象被销毁并释放内存)。
现在主要问题是:
new (this) example(source)
这条线让我很烦恼。这里发生了什么?
如果我被要求猜测,我会说正在创建一个新对象并将其指定为当前对象,我可以从this
关键字推断出来。
任何人都可以解决这个问题吗?究竟是怎么回事?
这种方法安全吗? (如果分配是动态发生的,程序员将来必须手动解除分配)
感谢。
答案 0 :(得分:3)
您所看到的是尝试代码重用。我们的想法是使用复制构造函数来实现赋值运算符(或者,在本例中为赋值函数)。
首先,摆脱简单的东西:
if
可确保正确处理自我分配(例如x.assign(x)
)。这是必要的,因为实施依赖于更改*this
不会更改source
这一事实。通过将this
与另一个对象的地址进行比较,这会测试对象是否相等,但是为了相同性。
该函数缺少return *this;
,但您可能已经注意到了这一点。
现在剩下的两行:
this->~example();
显式调用类example
的析构函数。在该行之后,this
指针不再指向一个对象,而是指向未sizeof(example)
的未初始化内存。
new (this) example(source);
是所谓的placement new,不分配内存,只是在example
指向的位置通过调用创建新的this
它的复制构造函数。在某种程度上,这是显式调用构造函数的语法,无需分配任何内存。
请注意,这会重复使用先前*this
所拥有的内存,无论它在哪里:它甚至可以是例如动态分配数组元素的virtual
基础...
关于安全性:在实践中,只要构造函数和析构函数都没有抛出,这就是安全的(尽管很难看并且可能效率不高)。但是,当你从一个试图偷偷摸摸的类派生时,你可能会遇到问题。
如果您想知道编写重用复制构造函数的赋值运算符/函数的最简单方法,请选中this question,其基本归结为:
example& assign(example source)
{
swap(*this, source);
return *this;
}
最重要的差异:
swap
异常安全(它们应该始终存在),则此代码是异常安全的。答案 1 :(得分:1)
这部分破坏了对象:
this->~example();
除了由于析构函数调用而释放的内存之外,它不会释放内存。然后,它继续调用" placement new":
new (this) example(source);
这将在前一个对象的(未发布的)内存上构造一个对象。
关于此的安全性,至少是危险的。如果在销毁对象后无法创建新对象,则会有一个奇怪的僵尸对象,当其正常生命周期结束时会再次被破坏(导致未定义的行为)。