27 October 2022

C++ 核心指南目录

C.61: A copy operation should copy

理由

这条指南讲的是一般人们使用时所假定的语义。在进行x = y操作后,我们得到结果 x == y

在赋值拷贝操作之后, xy 应该是独立的对象(值类型,非指针的内置类型和标准库类型的工作方式),或者, xy 指向一个共享的对象(指针类型,指针的工作方式)。

例子

using T = int;
using Bad = int;
class X {   // OK: value semantics
  public:
    X() {};
    X(const X&);     // copy X
    void copy(const T* src, const T* src_end, const T* dst) {};
    void modify() {};   // change the value of X
    // ...
    ~X() { delete[] p; };
    friend bool operator==(const X& a, const X& b);
  private:
    T* p{};
    int sz{};
};
bool equal(const T* a0, const T* a1, const T* b0, const T* b1) {
    return true;
}


bool operator==(const X& a, const X& b)
{
    return a.sz == b.sz && equal(a.p, a.p + a.sz, b.p, b.p + b.sz);
}

X::X(const X& a)
    :p{new T[a.sz]}, sz{a.sz}
{
    copy(a.p, a.p + sz, p);
}

int main()
{
    X x;
    X y = x;
    if (x != y) throw Bad{};
    x.modify();
    if (x == y) throw Bad{};   // assume value semantics
}

例子

class X2 {  // OK: pointer semantics
public:
    X2();
    X2(const X2&) = default; // shallow copy
    ~X2() = default;
    void modify();          // change the pointed-to value
    // ...
private:
    T* p;
    int sz;
};

bool operator==(const X2& a, const X2& b)
{
    return a.sz == b.sz && a.p == b.p;
}

X2 x;
X2 y = x;
if (x != y) throw Bad{};
x.modify();
if (x != y) throw Bad{};  // assume pointer semantics

注意

  • 尽量选择值类型,除非你要实现智能指针类型。值类型更简单,更容易分析,标准库也主要接收值类型的数据。