减少将临时对象分配给现场施工
Reducing assignment of temporary object to in-place construction
以支持移动语义的std::list
为例。
std::list<std::string> X;
... //X is used in various ways
X=std::list<std::string>({"foo","bar","dead","beef"});
自C++11以来,编译器完成赋值最直接的方法是:
- 销毁
X
- 构造
std::list
- 将
std::list
移动到X
现在,编译器不允许执行以下操作:
- 销毁X
- 施工
std::list
到位
因为虽然这显然节省了另一个memcpy
,但它消除了分配。使第二行为成为可能和可用的方便方法是什么?它在C++的未来版本中有计划吗?
我的猜测是,C++仍然没有提供这一点,除非写:
X.~X();
new(&X) std::list<std::string>({"foo","bar","dead","beef"});
我说得对吗?
您实际上可以通过定义operator=来获取初始值设定项列表。对于std::list,只需调用
X = {"foo","bar","dead","beef"}.
在你的情况下,实际发生的是:
- 构建临时
- 用临时
在大多数对象上,例如std::list,与简单地构建对象相比,这实际上并不昂贵。
然而,它仍然会对第二个std::list的内部存储进行额外的分配,这是可以避免的:如果可能的话,我们可以重用已经分配给X的内部存储。正在发生的是:
- 构造:临时为元素分配一些空间
- 移动:指针移动到X;X之前使用的空间被释放
一些对象重载赋值运算符以获取初始值设定项列表,std::vector和std::list就是这样。这样的操作员可以使用内部已经分配的存储,这是最有效的解决方案。
//请在这里插入关于过早优化的常见漫谈
它在C++的未来版本中有计划吗?
否。谢天谢地。
赋值是而不是与销毁然后创建相同。X
在您的作业示例中未被销毁。CCD_ 9是一个活动对象;X
的内容可能被破坏,但X
本身永远不会被破坏。
如果你想销毁X
,那么你有这个能力,使用显式析构函数和placementnew。尽管由于const
成员的可能性,如果您希望安全,您还需要清洗指向对象的指针。但是赋值不应该被认为是等价的。
如果您关心效率,那么最好使用assign
成员函数。通过使用assign
,X
有机会重用现有的分配。这几乎肯定会使它比你的"破坏加构造"版本更快。将一个链表移动到另一个对象中的成本是微不足道的;不得不销毁所有这些分配,只为再次分配而付出的代价并非如此。
这对于std::list
尤其重要,因为它有批的分配。
在最坏的情况下,assign
的效率不会低于你从课堂外想出的任何其他方法。最好的情况是,情况会好得多。
当您有一个涉及移动分配的语句时:
x = std::move(y);
在执行移动之前,不会为x
调用析构函数。然而,在移动之后,在某个时刻,将为y
调用析构函数。移动赋值运算符背后的思想是,它可能能够以一种简单的方式将y
的内容移动到x
(例如,将指向y
的存储的指针复制到x
)。它还必须确保其以前的内容被正确地销毁(它可以选择与y
交换,因为你知道y
可能不再使用,并且y
的析构函数将被调用)。
如果移动赋值是内联的,编译器可能能够推断出将存储从y
移动到x
所需的所有操作都相当于就地构造。
关于最后一个问题
”我说得对吗?
否。
你关于什么是允许的或不允许的想法是错误的。编译器可以替代任何优化,只要它保留了可观察的效果。这被称为"好像"规则。可能的优化包括删除所有代码,如果它不影响任何可观察到的内容。特别是,你对第二个例子的"不允许"是完全错误的,"它消除了任务"的推理也适用于你的第一个例子,你得出了相反的结论,即存在自相矛盾。
- 为什么 boost::interprocess::managed_shared_memory 在施工时会抛出 boost
- 施工期间的虚函数调用
- 施工后立即在向量上调用清晰?
- 安置回去在原地施工失败
- 施工中的自我参考
- 标准的哪一部分决定了现场成员与初始化器列表的优先级
- 高效的施工委托
- C GRPC ::完整的施工速度约为14K
- 减少将临时对象分配给现场施工
- C 在施工中定义的容器
- 在现场行走(从STL)
- 嵌入UI视图内部现场相机视图BlackBerry 10
- 过度施工
- 如何使用QTableView使用现场QCOMBOBOX
- 更改QT AbstractListModel而无需使用现场编辑
- 在施工时预留的标准集装箱?
- 延期构件施工
- 超载*操作员只能与一个施工人员一起工作
- 如何在工厂设计中支持多个施工签名
- std::lock_guard<std::mutex> 施工上的段错误?