由于拷贝构造

MyClass(const MyClass&);

和一个=操作过载

MyClass& operator = (const MyClass&);

具有几乎相同的代码,相同的参数,只有在返回不同,是有可能具有共同的功能对他们都使用?

有帮助吗?

解决方案

是。常见的有两种选择。一个 - 其通常气馁 - 是从复制构造显式调用operator=

MyClass(const MyClass& other)
{
    operator=(other);
}

然而,提供良好的operator=是一个挑战,当谈到与旧的国家,并从自我分配所产生的问题。此外,所有成员和基地得到默认初始化了的第一,即使他们是从other分配。这甚至可能不是适用于所有成员和碱以及即使它是有效的它在语义上是冗余的,并且可以是几乎昂贵。

一种日益流行的解决方案是使用复制构造函数和一个交换方法来实现operator=

MyClass& operator=(const MyClass& other)
{
    MyClass tmp(other);
    swap(tmp);
    return *this;
}

甚至:

MyClass& operator=(MyClass other)
{
    swap(other);
    return *this;
}

一个swap函数通常是简单写,因为它只是交换的内部的所有权和不必清理现有状态或分配新的资源。

复制和交换成语的优点是,它是自动自赋值安全 - 提供交换操作没有掷 - 也强烈异常安全

要成为强烈的异常安全,一“手”写赋值运算符通常有之前分配新资源的副本去分配受让人的旧资源,这样,如果发生异常,分配新的资源,旧的状态尚可归还。所有这些都为自由与复制和交换,但通常更复杂,因此容易出错,从头做。

有一两件事要小心的是,以确保交换法是一个真正的交换,而不是它使用拷贝构造函数和赋值操作符本身默认std::swap

典型地,成员逐一swap被使用。 std::swap作品是“无抛出”与所有的基本类型和指针类型的保证。大多数智能指针也可以无抛出保证交换。

其他提示

在复制构造执行曾经是原始内存对象的第一次初始化。赋值运算符,OTOH,覆盖以新的现有值。更多的时候比不,这涉及解聘老资源(例如,内存)和分配新的。

如果有两者之间的相似性,它是赋值操作符执行销毁和复制结构。一些开发商用于实际的就地销毁,然后放置拷贝构造器的任务。然而,这是一个的非常的坏主意。 (如果这是一个基类派生的类的分配期间调用的赋值运算符?)

什么通常被认为是规范成语时下使用swap查尔斯提示:

MyClass& operator=(MyClass other)
{
    swap(other);
    return *this;
}

本使用拷贝构造(注意other复制)和毁灭(它在函数结束破坏) - 和它使用他们在正确的顺序,太:建筑(可能会失败)破坏之前(不得失败)。

东西打扰我约:

MyClass& operator=(const MyClass& other)
{
    MyClass tmp(other);
    swap(tmp);
    return *this;
}

首先,读字“交换”时,我的心里都在想“复制”刺激我的常识。另外,我怀疑这个奇特招的目标。是的,在建造新(复制)资源的任何异常应该交换,这似乎是一个安全的方式,以确保所有新数据使得它去住之前被填充之前发生的。

这很好。那么,怎么样的交换之后发生的异常?从分配的用户的角度(当在临时对象超出范围的旧资源被破坏),该操作失败,但事实并非如此。它有一个巨大的副作用:副本实际上确实发生了。这是唯一失败的一些资源清理。目标对象的状态已经被改变即使操作从外表看来已失败。

所以,我建议,而不是“交换”做一个更自然的“转移”:

MyClass& operator=(const MyClass& other)
{
    MyClass tmp(other);
    transfer(tmp);
    return *this;
}

有仍然是临时对象的构造,但紧接着的下一个动作是移动之前释放目的地的所有当前资源(和调零所以他们不会是双释放)源的资源给它。

代替{构造,移动,自毁},我建议{构造,销毁,移动}。这一举措,这是最危险的动作,是一切已经尘埃落定之后最后采取的一个。

是,破坏失败是在任一方案中的问题。该数据已损坏(如果你不认为这是复制)或丢失(当你不认为这是释放)。失落的是比破坏更好。没有数据比坏数据更好。

转移,而不是交换。这就是我的建议呢。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top