为什么拷贝构造函数不需要检查输入对象是否指向自己?
Why does copy constructor not need to check whether the input object pointers to itself or not?
如下面的代码,复制赋值运算符必须检查输入对象是否指向自身。我想知道为什么复制构造函数不需要做同样的检查。
我是 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;
}
};
自赋值有时会发生,这是class.
正常使用的一部分
将一个尚未构造的对象作为参数传递给它自己的复制(或移动)构造函数是不正常的。虽然本身不是未定义的行为1,但没有充分的理由这样做,而且通常不会发生。它可能会意外发生,或者如果有人故意试图破坏您的 class.
因此,传统上复制(和移动)构造函数不会检查 &other != this
。
但是如果你想要一些额外的安全,没有什么能阻止你这样做:
rule_of_three(const rule_of_three& other) // copy constructor
{
assert(&other != this);
init(other.cstring);
}
1 [basic.life]/7
似乎允许这样做,只要您不访问尚未构建的对象本身。允许使用 &
获取地址。
假设您有像 Stormtroopers 这样的简单对象:
class Stormtrooper
{
char* cstring; // raw pointer used as a handle to a dynamically-allocated memory block
void clone(const char* s)
{
std::size_t n = std::strlen(s) + 1;
cstring = new char[n];
std::memcpy(cstring, s, n); // populate
}
public:
Stormtrooper(const char* s = "I am a Stormtrooper clone") { clone(s); }
~Stormtrooper()
{
delete[] cstring; // deallocate
}
Stormtrooper(const Stormtrooper& other) // copy constructor
{
clone(other.cstring);
}
Stormtrooper& operator=(const Stormtrooper& other) // copy assignment
{
if(this != &other) {
delete[] cstring; // deallocate
clone(other.cstring);
}
return *this;
}
};
如果您想将一个 Stormtrooper 分配给另一个 Stormtrooper,检查这两个 Stormtroopers 是否已经相同(通常是)很有用。通过这种方式,您可以避免 clone() 操作,因为 Stormtroopers 已经完全相同。
但是如果你想创建一个新的 Stormtrooper,并且你希望他与另一个 Stormtrooper 相同(像往常一样),你可以复制构建它,在这种情况下,clone() 操作将被正确执行。
通过这种方式,您可以轻松创建一整支冲锋队。
如下面的代码,复制赋值运算符必须检查输入对象是否指向自身。我想知道为什么复制构造函数不需要做同样的检查。
我是 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;
}
};
自赋值有时会发生,这是class.
正常使用的一部分将一个尚未构造的对象作为参数传递给它自己的复制(或移动)构造函数是不正常的。虽然本身不是未定义的行为1,但没有充分的理由这样做,而且通常不会发生。它可能会意外发生,或者如果有人故意试图破坏您的 class.
因此,传统上复制(和移动)构造函数不会检查 &other != this
。
但是如果你想要一些额外的安全,没有什么能阻止你这样做:
rule_of_three(const rule_of_three& other) // copy constructor
{
assert(&other != this);
init(other.cstring);
}
1 [basic.life]/7
似乎允许这样做,只要您不访问尚未构建的对象本身。允许使用 &
获取地址。
假设您有像 Stormtroopers 这样的简单对象:
class Stormtrooper
{
char* cstring; // raw pointer used as a handle to a dynamically-allocated memory block
void clone(const char* s)
{
std::size_t n = std::strlen(s) + 1;
cstring = new char[n];
std::memcpy(cstring, s, n); // populate
}
public:
Stormtrooper(const char* s = "I am a Stormtrooper clone") { clone(s); }
~Stormtrooper()
{
delete[] cstring; // deallocate
}
Stormtrooper(const Stormtrooper& other) // copy constructor
{
clone(other.cstring);
}
Stormtrooper& operator=(const Stormtrooper& other) // copy assignment
{
if(this != &other) {
delete[] cstring; // deallocate
clone(other.cstring);
}
return *this;
}
};
如果您想将一个 Stormtrooper 分配给另一个 Stormtrooper,检查这两个 Stormtroopers 是否已经相同(通常是)很有用。通过这种方式,您可以避免 clone() 操作,因为 Stormtroopers 已经完全相同。
但是如果你想创建一个新的 Stormtrooper,并且你希望他与另一个 Stormtrooper 相同(像往常一样),你可以复制构建它,在这种情况下,clone() 操作将被正确执行。
通过这种方式,您可以轻松创建一整支冲锋队。