Pet*_*ete 5 c++ copy-constructor assignment-operator
在我正在处理的项目的现有类中,我遇到了一些奇怪的代码:赋值运算符调用了复制构造函数.
我添加了一些代码,现在赋值运算符似乎会造成麻烦.如果我只使用编译器生成的赋值运算符,它工作正常.所以我找到了解决方案,但我仍然很想知道为什么这不起作用.
由于原始代码是数千行,因此我创建了一个更简单的示例供您查看.
#include <iostream>
#include <vector>
class Example {
private:
int pValue;
public:
Example(int iValue=0)
{
pValue = iValue;
}
Example(const Example &eSource)
{
pValue = eSource.pValue;
}
Example operator= (const Example &eSource)
{
Example tmp(eSource);
return tmp;
}
int getValue()
{
return pValue;
}
};
int main ()
{
std::vector<Example> myvector;
for (int i=1; i<=8; i++) myvector.push_back(Example(i));
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i].getValue();
std::cout << '\n';
myvector.erase (myvector.begin(),myvector.begin()+3);
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i].getValue();
std::cout << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是
myvector contains: 1 2 3 4 5
Run Code Online (Sandbox Code Playgroud)
但它应该是(事实上,如果我只使用编译器生成的赋值运算符)
myvector contains: 4 5 6 7 8
Run Code Online (Sandbox Code Playgroud)
Rei*_*ica 13
你operator=不会做每个人(包括标准库)认为它应该做的事情.它根本不会修改*this- 它只是创建一个新副本并返回它.
使用copy-and-swap惯用法在复制赋值运算符中重用复制构造函数是正常的:
Example& operator= (Example eSource)
{
swap(eSource);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
注意操作符如何按值获取其参数.这意味着将调用copy-constructor来构造参数,然后您可以只与该副本交换,有效地分配给*this.
另请注意,预计operator=将通过引用返回; 重载运算符时,始终遵循预期的约定.更重要的是,该标准实际上要求 a CopyAssignable或MoveAssignable类型的赋值运算符返回非const引用(C++ 11 [moveassignable]和[copyassignable]); 所以要正确使用带有标准库的类,必须遵守.
当然,它要求您swap()在类中实现一个函数:
void swap(Example &other)
{
using std::swap;
swap(pValue, other.pValue);
}
Run Code Online (Sandbox Code Playgroud)
该函数不应该引发异常(感谢@JamesKanze提到这一点),不要破坏异常的安全性operator=.
另请注意,应尽可能使用编译器生成的默认构造函数和赋值运算符; 他们永远不会与班级的内容不同步.在您的情况下,没有理由提供自定义的(但我认为该类是在此处发布的简化版本).
您找到的赋值运算符不正确。它所做的只是复制 的副本eSource,但它应该修改调用它的对象。
编译器为该类生成的赋值运算符相当于:
Example &operator= (const Example &eSource)
{
pValue = eSource.pValue;
return *this;
}
Run Code Online (Sandbox Code Playgroud)
对于此类,实现 没有意义operator=,因为编译器生成的版本基本上无法改进。但是,如果您确实实现了它,那么即使您以不同的方式编写它,这也是您想要的行为。
[Alf 会说 return void,大多数 C++ 程序员会说返回一个引用。无论您返回什么,重要的行为都是对pValuefrom 的值进行赋值eSource.pValue。因为这就是复制赋值运算符的作用:从源复制到目标。]