【发布时间】:2013-04-12 02:38:57
【问题描述】:
通用容器(如 Qt 容器中的容器)的共享内存/写入时复制实现是否被 C++11 移动语义和右值引用取代?
一个失败而另一个成功的地方在哪里?还是它们是互补而非替代?
【问题讨论】:
标签: c++ containers shared-memory rvalue-reference copy-on-write
通用容器(如 Qt 容器中的容器)的共享内存/写入时复制实现是否被 C++11 移动语义和右值引用取代?
一个失败而另一个成功的地方在哪里?还是它们是互补而非替代?
【问题讨论】:
标签: c++ containers shared-memory rvalue-reference copy-on-write
写入时复制和移动语义都已用于优化将数据保存在堆上的对象的值语义。例如,std::string 已实现为写入时复制对象和支持移动的对象。
因此,写时复制和移动语义在这方面是相似的:如果您足够松散地定义“复制”,它们都可以用于优化“复制”。我有时将移动语义描述为写时复制,引用计数被限制为 0 或 1,因此包含引用计数的字段被优化掉了。
std::lib 中的所有容器现在都使用移动语义,甚至以前允许使用写时复制的 std::string 现在也被禁止这样做。如果我今天要编写一个新的客户容器,我会在选择写时复制之前使用移动语义。
在 C++11 中仍然可以使用写时复制。如果您希望您的数据结构很少被写入,但经常被复制,并且许多客户持有相同值的副本,那么写时复制仍然是一个巨大的胜利。
例如,我看到写时复制很好地用于保存复杂文档的撤消列表。在任何给定的提交(您要保存状态的地方),自上次提交以来,只有一小部分大文档发生了变化。因此,制作文档副本以保存其状态意味着更新一堆引用计数,并实际对一小部分进行更改(写入时复制样式)。
【讨论】:
写时复制和移动语义是完全不同的概念,各自服务于不同的目的。虽然有一个常见的用例:从函数中返回一个对象,其中因为原始对象超出范围它实际上是一个移动,但在一般情况下它们不同:
在写入时复制多个同时处于活动状态的对象可以共享内容。使用移动语义,只有一个对象具有特定时间点的内容。
与此有点正交,写时复制在多线程环境中存在问题,因为可能有多个对象访问相同的数据(只读)和控制块(读/写),这需要在一个线程安全的方式。
【讨论】: