什么是复制和交换习语?
这个成语是什么,什么时候应该使用?它解决了哪些问题?当使用C ++ 11时,成语是否会改变?
虽然在许多地方已经提到过,但我们没有任何单一的“它是什么”问题和答案,所以在这里。以下是前面提到的地方的部分列表:
你最喜欢的C ++ Coding Style成语是什么:Copy-swap
在C ++中复制构造函数和=运算符重载:可能是一个常见的函数吗?
什么是复制省略以及如何优化复制和交换习惯用法
C ++:动态分配一个对象数组?
没有找到相关结果
已邀请:
4 个回复
徐百晴墓斜
应该永远不会失败,唯一可能失败的部分是复制构造。首先执行此操作,如果失败,则目标对象中不会更改任何内容。 在其精炼形式中,通过初始化赋值运算符的(非引用)参数来执行复制来实现复制和交换:
犀耽澄协吻
基本思想是: 分配给对象最容易出错的部分是确保获取新状态所需的任何资源(例如,内存,描述符) 如果获得新值的副本,则可以在修改对象的当前状态(即
)之前尝试获取,这就是为什么
被值接受(即复制)而不是通过引用 交换本地副本的状态
和
通常相对容易做到没有潜在的失败/异常,因为本地副本之后不需要任何特定的状态(只需要状态适合析构函数运行,就像对象一样)被移出> = C ++ 11) 什么时候应该使用? (它解决了哪些问题[/ create]?) 如果您希望被分配的对象不受引发异常的赋值的影响,假设您已经或可以写一个具有强异常保证的
,理想情况下一个不能失败/
..† 当你想要一个干净,易于理解,健壮的方法来定义赋值运算符(简单)复制构造函数,
和析构函数。 作为复制和交换完成的自我分配避免了被忽视的边缘情况。‡ 在分配期间通过拥有额外临时对象而产生的任何性能损失或暂时更高的资源使用对您的应用程序而言并不重要。 ⁂ †
投掷:通常可以通过指针可靠地交换对象跟踪的数据成员,但是没有无抛出交换的非指针数据成员,或者交换必须实现为
和复制构造的非指针数据成员或任务可能抛出,仍然有可能失败,留下一些数据成员交换而其他人没有。这个潜力甚至适用于C ++ 03
's,詹姆斯评论另一个答案: @wilhelmtell:在C ++ 03中,没有提到std :: string :: swap(由std :: swap调用)可能抛出的异常。在C ++ 0x中,std :: string :: swap是noexcept,不能抛出异常。 - 詹姆斯麦克尼利斯2010年12月22日15:24 ‡当从不同的对象分配时,分配运算符实现看起来很明智,很容易因自我分配而失败。虽然客户端代码甚至可能尝试自我分配似乎是不可想象的,但是在容器上的algo操作期间它可以相对容易地发生,其中
代码where50ѭ(可能仅适用于某些
分支)宏ala
或返回引用的函数到
,甚至(可能是低效但简洁的)代码,如
)。例如:
在自我分配时,上面的代码删除了
,在新分配的堆区域指向
,然后尝试读取其中未初始化的数据(未定义的行为),如果这没有做任何太奇怪的事情,
尝试自我分配到每一个刚被破坏的'T'! ⁂由于使用额外的临时(当运算符的参数是复制构造时),复制和交换习惯用法会引入效率低下或限制:
在这里,手写的
可能会检查
是否已经连接到与
相同的服务器(如果有用,可能会发送“重置”代码),而复制和交换方法会调用可能是复制构造函数的复制构造函数。写入打开一个独特的套接字连接然后关闭原来的。这不仅意味着远程网络交互而不是简单的进程内变量复制,它可能会对套接字资源或连接的客户端或服务器限制产生影响。 (当然这个类有一个非常可怕的界面,但那是另一回事;-P)。
坛沤疲撑拆
函数,如下所示:
...当你调用
函数时,编译器会对你大喊: 这与调用的
函数和
对象作为参数传递有关。 解决这个问题的方法是不使用
关键字并重新定义
函数:
这次,您只需调用
并传入
,从而使编译器满意: 毕竟,您不需要使用
函数来交换2个对象。使
成为具有一个
对象作为参数的成员函数同样有意义。 您已经可以访问
对象,因此将其作为参数传递在技术上是多余的。
外镶受继
,其中
是一些有状态的分配器类型,我们将比较以下函数:
两个函数
和
的目的是给
最初的状态。然而,有一个隐藏的问题:如果
会发生什么?答案是:这取决于。我们来写
。 如果
是
,则
将
的分配器重新分配给
,否则不重新分配,并且
继续使用其原始分配器。在这种情况下,数据元素需要单独交换,因为
和
的存储不兼容。 如果
是
,那么
以预期的方式交换数据和分配器。 如果
是
,那么我们需要动态检查。 如果是
,则两个容器使用兼容存储,并以通常的方式进行交换。 但是,如果
,则程序具有未定义的行为(参见[container.requirements.general / 8]。 结果是,只要容器开始支持有状态分配器,交换就变成了C ++ 11中的一个非常重要的操作。这是一个有点“高级用例”,但并非完全不可能,因为一旦您的类管理资源,移动优化通常只会变得有趣,而内存是最受欢迎的资源之一。