这是好的代码吗?(复制构造函数和赋值运算符)

mpe*_*pen 10 c++ operator-overloading copy-constructor

由于某种原因,我不得不为我的班级提供复制构造函数和operator =.operator=如果我定义了一个副本ctor,我想我不需要,但是QList想要一个.把它放在一边,我讨厌代码重复,所以这样做有什么不对吗?

Fixture::Fixture(const Fixture& f) {
    *this = f;
}

Fixture& Fixture::operator=(const Fixture& f) {
    m_shape         = f.m_shape;
    m_friction      = f.m_friction;
    m_restitution   = f.m_restitution;
    m_density       = f.m_density;
    m_isSensor      = f.m_isSensor;
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

只是出于好奇,没有办法切换它,以便大部分代码都在复制文件中并operator=以某种方式利用它?我尝试过,return Fixture(f);但不喜欢那样.


看来我需要更清楚地说明复制构造函数和赋值运算符已被我继承的类隐式禁用.为什么?因为它是一个抽象的基类,不应该自己实例化.然而,这门课程独立的.

Joh*_*itb 25

这很糟糕,因为operator=不再依赖于设置对象.你应该反过来做,并可以使用复制交换习语.

如果您只需要复制所有元素,则可以使用隐式生成的赋值运算符.

在其他情况下,您将不得不另外做一些事情,主要是释放和复制内存.这就是复制交换习惯用法的好处.它不仅优雅,而且还提供如此分配,如果只交换原语,则不会抛出异常.让我们指向一个需要复制的缓冲区:

Fixture::Fixture():m_data(), m_size() { }

Fixture::Fixture(const Fixture& f) {
    m_data = new item[f.size()];
    m_size = f.size();
    std::copy(f.data(), f.data() + f.size(), m_data);
}

Fixture::~Fixture() { delete[] m_data; }

// note: the parameter is already the copy we would
// need to create anyway. 
Fixture& Fixture::operator=(Fixture f) {
    this->swap(f);
    return *this;
}

// efficient swap - exchanging pointers. 
void Fixture::swap(Fixture &f) {
    using std::swap;
    swap(m_data, f.m_data);
    swap(m_size, f.m_size);
}

// keep this in Fixture's namespace. Code doing swap(a, b)
// on two Fixtures will end up calling it. 
void swap(Fixture &a, Fixture &b) {
  a.swap(b);
}
Run Code Online (Sandbox Code Playgroud)

这就是我通常编写赋值运算符的方式.读取想要的速度?传递有关异常赋值运算符签名的值(按值传递).

  • 在交换之前,你想要的值是`f`,但你想要它们在`*this`中.这就是你交换的原因.如果你保持`f`是一个const引用,那么你必须做`Fixture c = f; 交换(*this,c);`在体内 - *所以你必须复制*.最好尽可能透明地向来电者提供副本.阅读http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ (2认同)
  • 我觉得它变得越来越优雅了:哦 (2认同)
  • 等等 - 我们真的在这里忽略了一些东西:你需要*交换,因为你想要释放你的旧日期.如果您只是分配,则不会释放旧数据.如果您只是交换指针而不是其他数据,那么在参数的析构函数中(它将保存您的旧指针,但其他一些数据),您将得到不一致.所以你必须总是交换. (2认同)

Ale*_*lli 8

复制ctor和赋值完全不同 - 赋值通常需要释放它所替换的对象中的资源,复制ctor正在处理一个尚未初始化的对象.从那以后你显然没有特殊要求(转让时不需要"释放"),你的方法很好.更一般地说,你可能有一个"对象所持有的所有资源"辅助方法(在dtor和分配开始时调用)以及"将这些其他东西复制到对象中"这一部分相当接近一个典型的复制ctor(或大部分,无论如何;-)的工作.


sel*_*tze 6

您只是在示例中执行成员明确的复制和分配.这不是你自己需要写的东西.编译器可以生成完全相同的隐式复制和赋值操作.如果编译器生成的那些不合适,你只需要编写自己的拷贝构造函数,赋值和/或析构函数(例如,如果你通过指针管理某些资源或类似的东西)