为什么我们在使用赋值运算符时使用copy和swap?

时间:2016-10-01 13:08:22

标签: c++ operator-overloading copy-constructor assignment-operator copy-and-swap

使用copy-and-swap方法时,我对赋值运算符有疑问。

String & operator = (String s) // the pass-by-value parameter serves as a temporary
{
   s.swap (*this); // Non-throwing swap
   return *this;
}// Old resources released when destructor of s is called.

假设我们有一个很好的复制构造函数,可以深层复制所有指针和动态分配的变量。

那么,上面的代码和下面的代码之间有什么区别?

String & operator = (String s) // the pass-by-value parameter serves as a temporary
{
   return s;
}

因为我们有一个很好的复制构造函数,我认为在operator = function中创建了另一个对象s。 那么,使用非抛出交换函数有什么意义呢?

3 个答案:

答案 0 :(得分:3)

主要区别在于第二个operator=根本不会更改当前对象(即*this)。

String a, b;
b = a; // b is not changed at all

请注意,第二个operator=将通过引用返回s(在退出函数时将被销毁),因此它只是一个悬空引用。

更一般地说,我们使用copy & swap idiom来提供强大的异常安全保证,这类似于提交或回滚语义;如果操作因异常而终止,则程序状态将保持不变。

String & operator = (String s) // Copy construct s. If exception happens here, 
                               // s won't be constructed, 
                               // and the state of the current object (*this) won't be changed
{
   s.swap (*this);             // Use non-throwing swap to commit the change
   return *this;               // Non-throwing operation
}

答案 1 :(得分:0)

不同之处在于,在第二个代码块中,您创建s对象的副本String,返回对它的引用,然后在范围退出时销毁该副本,这会导致您的程序有不明确的行为。

答案 2 :(得分:0)

有几个主要区别:

赋值运算符应返回*this(并且几乎总是如此)。这就是使链接分配成为可能的原因。

String s1, s2, s3;
s1 = s2 = s3; // Now all strings ave the same value.

而是返回对局部变量的引用。然后它变成悬空参考,因为它没有指向有效的存储位置。

此外,赋值运算符必须更改已分配的对象,这在代码中不会发生。

最后,为什么我们需要非投掷交换呢?让我们假设您的赋值运算符抛出异常。分配失败后分配的对象的状态是什么?

某些实现可能会导致对象处于无效状态,因为在更改它时会抛出异常。

这是交换进入的地方。因为交换从不抛出,我们可以确定分配的对象处于有效状态。如果在交换之前抛出异常,则该对象仍具有其旧值,如果它在交换之后,则该对象具有其新值。