繁体   English   中英

手写动作

[英]Hand written move

我写了一个向量 class 来学习移动语义。 我使用移动构造函数来移动 T(注释行)。

我的问题是为什么不只复制 temp object 的所有字节并将 temp object 的所有字节设置为零,就像在 C 中一样?

我知道将为 temp object 调用析构函数,它可能需要一些初始化的成员才能正确析构。 这就是为什么我不能更改 object 的内部表示的原因。

但是如果我 100% 确定我的 ~T() 没有这样的要求,这是一个很好的优化吗?

 20     void push_back(T&& val)
 21     {
 22         check_cap();
 23         //new (m_data + m_size) T(std::move(val));
 24         for(int i = 0; i < sizeof(T); ++i)
 25         {
 26             reinterpret_cast<char*> (m_data + m_size)[i] = reinterpret_cast<char*> (&val)[i];
 27             reinterpret_cast<char*> (&val)[i] = 0;
 28         }
 29         m_size++;
 30     }

(如果与实际问题无关,请不要告诉任何有关演员阵容及其安全性的内容)

(我知道这不是一个好方法,最好不要在实际项目中使用它。但我只感兴趣从效率的角度来看它有多好。)

为什么不只复制 temp object 的所有字节并将 temp object 的所有字节设置为零,就像在 C 中一样?

这是一个很好的优化吗?

我想不是。 这是您的手写版本和使用clang++的普通版本之间的快速基准比较:

在此处输入图像描述

使用g++时,结果是平局,因此也没有任何收获。

你的计划很糟糕。

使用as-if 规则,编译器通常可以计算出 memcpy 和零 - 甚至只是跳过析构函数 - 是合法的。

如果这样的编译器遇到您手工制作的未定义行为,它要么被未定义行为混淆,要么因此无法进一步优化。


有时有充分的理由诉诸未定义的行为。 但他们首先要证明您的解决方案能让事情变得更好,然后用尽符合标准的解决方案。 最后,他们坦诚地讨论了真正的短期、中期和长期风险,以换取短期的保证收益。

你的案子没有这些。

将 move-destroy 优化到 memcpy 是编译器已经对在简单代码流中易于理解的类型进行的操作。 手动操作是 99/100 毫无意义和 90/100 倍有害。

如果您的类型不简单并且代码流易于理解,那么您的优化可能也难以证明是安全的。 如果你简化你的类型和代码流,当你可以可靠地证明你的 memcpy 零是最优的时,你的编译器可能也可以。

坐下来与godbolt一起玩优化编译器output。 这是有教育意义的。

您的优化可能对少数情况有效。 当您的移动构造函数执行特定操作时,它可能会导致问题。

 class MyCustomClass : public IObserver
 {
     Registry &registry;
     // ...
 public:
     MyCustomClass(MyCustomClass &&rhs)
     : registry{rhs.registry}
     {
          registry.register(*this);
     }
     // ...
 };

如果您按位复制此 class,则移动的实例未在注册表中注册。

通过归零,引用被破坏,原始实例的析构函数很可能在从注册表中注销时崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM