作为下面的代码,复制分配运算符必须检查输入对象是否指向自身。我想知道为什么复制构造函数不需要执行相同的检查。
我是C ++的新手。对于这个问题,我将不胜感激。
class rule_of_three
{
char* cstring; // raw pointer used as a handle to a dynamically-allocated memory block
void init(const char* s)
{
std::size_t n = std::strlen(s) + 1;
cstring = new char[n];
std::memcpy(cstring, s, n); // populate
}
public:
rule_of_three(const char* s = "") { init(s); }
~rule_of_three()
{
delete[] cstring; // deallocate
}
rule_of_three(const rule_of_three& other) // copy constructor
{
init(other.cstring);
}
rule_of_three& operator=(const rule_of_three& other) // copy assignment
{
if(this != &other) {
delete[] cstring; // deallocate
init(other.cstring);
}
return *this;
}
};
Self-assignment有时会发生,这是类的正常使用的一部分。
将尚未构造的对象作为参数传递给其自己的副本(或移动)构造函数是不正常的。尽管本身不是未定义的行为1,但没有充分的理由这样做,并且通常不会发生。这可能是偶然发生的,或者是有人故意破坏您的课程。
因此,传统上复制(并移动)构造函数不检查&other != this
。
但是,如果您需要额外的安全性,没有什么可以阻止您这样做:
rule_of_three(const rule_of_three& other) // copy constructor
{
assert(&other != this);
init(other.cstring);
}
[[1 [basic.life]/7
似乎允许这样做,只要您不访问尚未构造的对象本身即可。允许使用[basic.life]/7
获取其地址。
假设您有简单的对象,例如突击队:
&
如果要将一个突击队员分配给另一个突击队员,检查两个突击队员是否已经相同(通常是相同的)会很有用。这样就避免了clone()操作,因为Stormtroopers已经完全相同。
但是,如果您要创建一个新的Stormtrooper,并且希望他与另一个Stormtrooper相同(照常),则可以对其进行复制构造,在这种情况下,clone()操作将正确执行。
通过这种方式,您可以很容易地组建一支完整的突击部队。