为什么"移动语义"而不是简单的memcpy?

时间:2015-09-02 12:14:12

标签: c++ c++11 c++17

给出以下代码:

typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_t;

//this moves the back of src to the back of dst:
void push_popped(std::list<storage_t> & dstLst, std::list<storage_t> & srcLst)
{
  auto & src = srcLst.back();
  dstLst.push_back(storage_t());
  auto & dst = dstLst.back();
  std::memcpy(&dst, &src, sizeof(T));
  srcLst.pop_back();
}

我清楚地知道为什么这种方法通常不正确的3个原因(即使它避免调用src->~T(),因此避免了T的双重回收资源)。

  1. 类型为U*的对象成员,指向同一对象的其他U成员
  2. 隐藏的类成员可能需要更新(例如vtable)
  3. 系统需要记录T处不再存在src,而T
  4. 现在存在dst

    (这里提到这些:http://www.gamedev.net/topic/655730-c-stdmove-vs-stdmemcpy/#entry5148523。)

    假设T不是一个类型,其内存地址是其状态的属性(例如std::mutexstd::condition_variable),这些是这种方法的唯一问题吗?还是有其他可能出错的事情?我想描述未知问题。

    我想我有一个&#34;对象重定位语义&#34;已经发展了,但我不想让人们考虑它是否有明显的漏洞。

2 个答案:

答案 0 :(得分:4)

&#34;平易可复制的概念&#34;意味着memcpy是安全的。您可以通过std中的特征测试类型是否可以轻易复制。

它包括摧毁它是一个noop的想法;在你的情况下,你希望破坏不是一个noop,而是在源上完成,而不是在dest上完成。

&#34;移动和破坏源&#34;的概念已经在C ++ 1z标准化过程中提出,独立于&#34;可复制的&#34;概念。建议用于例外安全;有些类型的move-construct不是异常安全的,但是move-construct-and-destroy-source也是如此。并且存在涉及异常和容器分配的棘手问题,使得noexcept move-ctor操作非常有价值。

如果它符合标准,那么如果它被证明有价值的话,那么一个简单的可复制的 - 如果你没有 - 破坏 - 源概念也可以添加到标准中。

它不适用于所有移动语义都可以增强的东西,并且它可能需要程序员的努力(编译器如何能够解决这个问题&#34;可以让驱逐舰消失&#34;是不容易;图灵机行为的所有非平凡的非结构属性都是难以处理的。)

答案 1 :(得分:1)

为什么使用Copy构造函数而不是std::memcpy
移动构造函数/移动赋值oeprator为您提供封装的操作,以便在移动对象时执行其他有用的操作 - 记录,清理等。

性能明智 - 在许多情况下,编译器可以将许多移动优化为仅一个(想象许多函数只是简单地从一个对象返回一些对象)。 memcpy他们的罪行受到更多限制。

最后 - 因为C ++不是关于移动字节 - 它是关于使用对象作为程序的基础。