首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >手写移动

手写移动
EN

Stack Overflow用户
提问于 2020-12-30 13:49:26
回答 3查看 145关注 0票数 3

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

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

我知道会为temp对象调用析构函数,它可能需要一些初始化的成员才能正确地进行析构。这可能是我不能更改对象的内部表示形式的原因。

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

代码语言:javascript
复制
 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     }

(如果它与实际问题无关,请不要告诉任何关于转换及其安全性的信息)

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-12-30 14:20:50

为什么不复制temp对象的所有字节,并将temp对象的所有字节设置为零,就像C中的那样? 这是一个很好的优化吗?

我不这么认为。下面是一个使用快板凳的手写版本和普通版本的clang++比较

当使用g++时,结果是领带,因此也没有任何增益。

票数 6
EN

Stack Overflow用户

发布于 2020-12-30 17:27:08

你的计划很糟糕。

编译器可以使用如果规则计算出一个memcpy和一个零--甚至只是跳过析构函数--是合法的。

如果这样的编译器运行在手工构建的未定义行为中,它要么会被未定义的行为弄糊涂,要么会因此而无法进一步优化。

有时有充分的理由诉诸于不明确的行为。但是他们首先证明了您的解决方案使更好,并且耗尽了标准的兼容解决方案。最后,他们坦率地讨论了真正的短期、中期和长期风险,以换取短期的有保障的利益。

你的案子跟这一切无关。

优化移动-破坏到memcpy是编译器已经做的类型,很容易理解在简单的代码流。手工操作是无意义的99/100,90/100倍有害。

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

坐下来,然后使用优化的编译器输出。是有教育意义的。

票数 4
EN

Stack Overflow用户

发布于 2020-12-30 14:40:18

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

代码语言:javascript
复制
 class MyCustomClass : public IObserver
 {
     Registry &registry;
     // ...
 public:
     MyCustomClass(MyCustomClass &&rhs)
     : registry{rhs.registry}
     {
          registry.register(*this);
     }
     // ...
 };

如果您按位复制这个类,则所移动的实例没有在注册表中注册。

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65508044

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档