提问人:MPelletier 提问时间:11/14/2009 最后编辑:CerbrusMPelletier 更新时间:10/4/2023 访问量:100328
复制构造函数和 C++ 中的 = 运算符重载:是否可以使用通用函数?
Copy constructor and = operator overload in C++: is a common function possible?
问:
由于复制构造函数
MyClass(const MyClass&);
和 = 运算符重载
MyClass& operator = (const MyClass&);
具有几乎相同的代码,相同的参数,并且仅在返回值上有所不同,是否可以有一个共同的函数供它们使用?
答:
是的。有两种常见的选择。一种 - 通常不鼓励 - 是显式调用 from 复制构造函数:operator=
MyClass(const MyClass& other)
{
operator=(other);
}
然而,在处理旧状态和自我分配引起的问题时,提供商品是一个挑战。此外,所有成员和基都首先初始化默认值,即使它们要分配给 。这甚至可能对所有成员和基地都无效,即使有效,它在语义上也是多余的,而且实际上可能很昂贵。operator=
other
一种越来越流行的解决方案是使用 copy 构造函数和 swap 方法实现。operator=
MyClass& operator=(const MyClass& other)
{
MyClass tmp(other);
swap(tmp);
return *this;
}
甚至:
MyClass& operator=(MyClass other)
{
swap(other);
return *this;
}
函数通常编写起来很简单,因为它只是交换内部的所有权,而不必清理现有状态或分配新资源。swap
复制和交换习惯的优点是它自动自分配安全,并且 - 如果交换操作是无抛出的 - 也是非常安全的异常。
为了实现强烈的异常安全,“手写”分配操作员通常必须在取消分配被分配者的旧资源之前分配新资源的副本,以便在分配新资源时发生异常,仍然可以返回到旧状态。所有这些都是免费的,但从头开始通常更复杂,因此容易出错。
需要注意的一件事是确保 swap 方法是真正的 swap,而不是使用 copy 构造函数和赋值运算符本身的默认值。std::swap
通常使用成员。 所有基本类型和指针类型都有效并保证“无抛出”。大多数智能指针也可以通过无抛保证进行交换。swap
std::swap
评论
operator=
assign
复制构造函数对以前是原始内存的对象执行首次初始化。赋值运算符 OTOH 用新值覆盖现有值。这通常涉及消除旧资源(例如内存)并分配新资源。
如果两者之间有相似之处,那就是赋值运算符执行销毁和复制构造。一些开发人员过去常常通过就地销毁,然后放置复制构造来实现分配。但是,这是一个非常糟糕的主意。(如果这是在派生类赋值期间调用的基类的赋值运算符,该怎么办?
现在通常被认为是规范的成语,正如查尔斯所建议的那样:swap
MyClass& operator=(MyClass other)
{
swap(other);
return *this;
}
这使用复制构造(注意是复制的)和销毁(在函数结束时销毁)——并且它也以正确的顺序使用它们:在销毁(一定不能失败)之前构造(可能失败)。other
评论
swap
virtual
有些事情困扰着我:
MyClass& operator=(const MyClass& other)
{
MyClass tmp(other);
swap(tmp);
return *this;
}
首先,当我的大脑在思考“复制”时,读到“交换”这个词会激怒我的常识。另外,我质疑这个花哨的把戏的目标。是的,在构建新(复制)资源时出现的任何异常都应该发生在交换之前,这似乎是一种安全的方法,可以确保所有新数据在上线之前都已填充。
没关系。那么,交换后发生的异常怎么办?(当临时对象超出范围时,旧资源被销毁时)从分配用户的角度来看,操作已失败,但未失败。它有一个巨大的副作用:复制确实发生了。只是一些资源清理失败了。目标对象的状态已更改,即使从外部看操作似乎已失败。
所以,我建议不要“交换”,而是做一个更自然的“转移”:
MyClass& operator=(const MyClass& other)
{
MyClass tmp(other);
transfer(tmp);
return *this;
}
临时对象的构造仍然存在,但下一个直接操作是在将源资源移动到目标之前释放目标的所有当前资源(以及 NULLing,以便它们不会被双重释放)。
我建议 { construct, destruct, move } 代替 { construct, move, destruct }。此举是最危险的行动,是在其他一切都解决后最后采取的行动。
是的,在任何一种方案中,销毁失败都是一个问题。数据要么损坏(在您认为不是时复制)要么丢失(在您认为不是时释放)。迷失总比腐败好。没有数据总比坏数据好。
转移而不是交换。无论如何,这是我的建议。
评论
First, reading the word "swap" when my mind is thinking "copy" irritates
my mind
评论