C++ 如果复制构造函数的所有功能都可以使用'=';?

C++ 如果复制构造函数的所有功能都可以使用'=';?,c++,C++,复制ctor基本上使用以前创建的对象创建对象。 但是,如果我们只是创建一个对象,然后使用“=”进行逐个元素的赋值,会怎么样呢。即使对象是动态创建的,也可以这样做。那么,复制构造函数可以做什么,而赋值操作符却做不到呢?有很多很好的理由使用复制构造函数,而不是默认地构造一个空对象,而不是将新对象赋值给一些已经存在的对象 理由一。常数正确性 首先,让我们做一个魔鬼倡导者,在不重要的情况下考虑这个问题: struct X { int i; }; X x; x.i = 10; X y; y =

复制ctor基本上使用以前创建的对象创建对象。
但是,如果我们只是创建一个对象,然后使用“=”进行逐个元素的赋值,会怎么样呢。即使对象是动态创建的,也可以这样做。那么,复制构造函数可以做什么,而赋值操作符却做不到呢?

有很多很好的理由使用复制构造函数,而不是默认地构造一个空对象,而不是将新对象赋值给一些已经存在的对象

理由一。常数正确性 首先,让我们做一个魔鬼倡导者,在不重要的情况下考虑这个问题:

struct X {
    int i;
};

X x;
x.i = 10;
X y; 
y = x;  // Option 1 
X y(x) // Option 2
在上面的例子中,选项1和选项2之间实际上没有什么区别,除了更好的可读性和代码推理。但是,如果我们想让我们的
y
对象成为
const
对象,因为我们不希望它在其生命周期内发生变化,该怎么办?选项1无效:

const X y;
y = x; // Compilation error!
因此,即使在最简单的例子中,我们也可以看出,即使对于非常简单的类型,区分赋值和复制构造对于常量正确性也是非常重要的。(对于同一点,可能还有其他例子)

理由2。代码效率 接下来是性能影响。让我们考虑一个非常坏的和不正确的String类的实现(仅说明,在生命中没有其他地方):

在上面的示例中,选项1会导致重复工作—首先分配缓冲区,然后释放缓冲区,然后再次分配缓冲区。在选项2中,缓冲区只分配一次。因此,第二点:复制构造函数有助于生成效率更高的代码

理由3。正确性

现在,让我们考虑一下断弦。虽然它在很多层面上都是错误的,但一段特别糟糕的代码是它的赋值运算符。它删除原始缓冲区,然后分配一个新的缓冲区,从

rhs
复制数据。两个主要问题是,如果
rhs
this
相同,则删除后将没有可复制的内容。第二个问题是,如果出于任何原因,新的分配抛出了一个异常(例如,内存不足),我们就已经失去了原始缓冲区。虽然第一个问题可以通过检查自分配来解决(
if(&rhs==this)return*this;
),但第二个问题无法简单地解决。人们可以在不同的文章中阅读如何编写赋值运算符,但(对于本类)约定的方法如下:

// Rest of BrokenString remains the same
NotSoBrokenString& operator= (const NotSoBrokenString& rhs) {
    NotSoBrokenString temp(rhs);
    char* const buf = buffer;
    buffer = temp.buffer;
    temp.buffer = buf;
}
这要好得多,因为所有的分配都在
temp
构造函数中。如果失败-抛出异常-原始缓冲区保持有效和可用。(它还解决了自我分配的问题-当
rhs
相同时不会造成伤害,尽管效率稍低)。 所以,第三点赋值运算符通常是根据复制构造函数来完成的

现在这个答案变得相当大了,所以我没有这个例子,但是类的语义通常允许它被复制构造,而不是赋值

结论
复制构造函数优于赋值运算符的优点包括常量正确性、效率、代码正确性以及对非平凡语义的支持。

构造一个对象。复制构造函数是否更有效?如果是这样的话,那为什么呢?这就像问电脑是否比割草机更高效。在什么方面效率更高?什么时候没有意义。与赋值运算符相比,复制元素值更有效。我不确定副本是否真正解决了这个问题。它解释了差异,但并没有真正提供一个示例说明为什么需要它——为什么不能简单地默认构造一个空对象,然后将现有对象复制给新对象。我将投票重新讨论这个问题,如果它得到重新讨论,我将尝试从这个角度回答。
// Rest of BrokenString remains the same
NotSoBrokenString& operator= (const NotSoBrokenString& rhs) {
    NotSoBrokenString temp(rhs);
    char* const buf = buffer;
    buffer = temp.buffer;
    temp.buffer = buf;
}