MPe*_*ier 81 c++ c++-faq variable-assignment copy-constructor
自复制构造函数
MyClass(const MyClass&);
Run Code Online (Sandbox Code Playgroud)
和=运算符重载
MyClass& operator = (const MyClass&);
Run Code Online (Sandbox Code Playgroud)
有几乎相同的代码,相同的参数,只有不同的返回,是否有可能有一个共同的功能,他们都使用?
CB *_*ley 114
是.有两种常见的选择.一个 - 通常不鼓励 - 是operator=显式调用复制构造函数:
MyClass(const MyClass& other)
{
operator=(other);
}
Run Code Online (Sandbox Code Playgroud)
然而,operator=在处理旧状态和自我分配引起的问题时,提供商品是一项挑战.此外,即使要将其分配给,所有成员和基础也会首先进行默认初始化other.这甚至可能对所有成员和基地都无效,即使它有效,它在语义上也是多余的,并且可能实际上很昂贵.
越来越流行的解决方案是operator=使用复制构造函数和交换方法来实现.
MyClass& operator=(const MyClass& other)
{
MyClass tmp(other);
swap(tmp);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
甚至:
MyClass& operator=(MyClass other)
{
swap(other);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
一个swap函数通常是简单的写,因为它只是交换了内部的所有权,并没有清理现有状态或分配新的资源.
复制和交换习惯用法的优点是它可以自动进行自我分配安全 - 并且 - 假设交换操作是无抛出的 - 也非常安全.
为了强烈异常安全,"手写"赋值运算符通常必须在取消分配受让人的旧资源之前分配新资源的副本,以便在分配新资源时发生异常,旧状态仍然可以返回到.所有这些都是免费提供的复制和交换,但通常更复杂,因此容易出错,从头开始.
要注意的一件事是确保交换方法是真正的交换,而不是std::swap使用复制构造函数和赋值运算符本身的默认值.
通常使用成员swap方式.std::swap所有基本类型和指针类型都可以保证"无法投入".大多数智能指针也可以与无投掷保证交换.
sbi*_*sbi 13
复制构造函数执行以前是原始内存的对象的首次初始化.赋值运算符OTOH使用新值覆盖现有值.通常,这涉及到解雇旧资源(例如,内存)和分配新资源.
如果两者之间存在相似性,则赋值运算符执行销毁和复制构造.一些开发人员过去常常通过就地破坏实现赋值,然后是贴片复制构造.但是,这是一个非常糟糕的主意.(如果这是在派生类的赋值期间调用的基类的赋值运算符,该怎么办?)
swap正如查尔斯建议的那样,现在通常被认为是典型的习语:
MyClass& operator=(MyClass other)
{
swap(other);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
这使用了复制构造(注释other被复制)和销毁(它在函数末尾被破坏) - 它也以正确的顺序使用它们:构造(可能在失败之前失败)(绝不能失败).