CppCoreGuidelines C.60 拷贝赋值/复制赋值函数应为非虚的,并接受 const& 参数,返回非 const& 结果
25 October 2022
“Make copy assignment non-virtual, take the parameter by const&, and return by non-const&”
理由
如此操作,简单高效。如想针对 rvalue 右值进行优化,可提供一个重载的函数,接受一个 && 右值引用作为参数。
例子
class Foo { public: Foo& operator=(const Foo& x) { // GOOD: no need to check for self-assignment (other than performance) auto tmp = x; swap(tmp); // see C.83 return *this; } // ... }; Foo a; Foo b; Foo f(); a = b; // assign lvalue: copy a = f(); // assign rvalue: potentially move
注意
swap 实现技术提供有效保障。
例子
但是,如果你想要避免临时副本,获取更好的性能。考虑一个简单的 Vector 情况,包含元素比较多,且大小一样的 Vector 之间赋值的情况就比较常见。这种情况,用 swap 实现就会导致比较大的性能开销。
template<typename T> class Vector { public: Vector& operator=(const Vector&); // ... private: T* elem; int sz; }; Vector& Vector::operator=(const Vector& a) { if (a.sz > sz) { // ... use the swap technique, it can't be bettered ... return *this; } // ... copy sz elements from *a.elem to elem ... if (a.sz < sz) { // ... destroy the surplus elements in *this and adjust size ... } return *this; }
通过直接改写目标元素,我们不能像 swap 技术那样实现完备的保证,只能达到基础保证。所以需要注意自己给自己赋值这种情况。
其他选项:
如果你需要一个虚的赋值操作符,但是明白可能有深层次的问题,那可以不称之为 operator=
,而取名为 virtual void assign(const Foo&)
强化
- (简单)赋值操作符必须是 virtual 的。小心恶龙。
- (简单)赋值操作符要返回 T&,从而可以串接起来使用。不要用 const T&,这样会影响代码编排以及把对象放入容器。
- (中等难度)赋值操作符应该(隐式或显示)地调用基类和成员的赋值操作符。查看析构函数确定类型是否有指针语义或值语义。