为什么"move semantics"而不是简单的memcpy?

Why "move semantics" rather than simply memcpy?

本文关键字:简单 memcpy move semantics 为什么      更新时间:2023-10-16

给定以下代码:

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. 隐藏的类成员可能需要更新(例如,虚表)
  3. 系统需要记录Tsrc不再存在,T现在在dst存在

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

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

我想我已经开发了一个"对象重定位语义",但如果它有一个明显的漏洞,我宁愿不要求人们考虑它。

"trivial copyable"的概念暗示内存是安全的。你可以通过std中的trait来测试一个类型是否可复制。

它包含了破坏它是一个noop的想法;在您的情况下,您希望销毁不是一个noop,而不是在源上执行,而在目标上执行。

move & destroy-source的概念已在c++ 1z标准化过程中提出,独立于"平凡的可复制"。的概念。它是为了异常安全而提出的;有些类型的move-construct不是异常安全的,但是move-construct-and-destroy-source可以。还有一些棘手的问题涉及异常和容器分配,这使得noexcept move- tor操作非常有价值。

如果这被纳入标准,那么如果证明是有价值的,那么一个微不足道的"如果你不破坏源代码,就可以复制"的概念也可以被添加到标准中。

它不会适用于所有移动语义可以增强的东西,并且它可能需要程序员的努力(编译器如何能够计算出"省略销毁器"是可以的);这并不容易;图灵机行为的所有非平凡非结构性质都是难以处理的

为什么使用复制构造函数而不是std::memcpy ?
Move构造函数/Move赋值操作符为您提供了在移动对象时做一些其他有用的事情的封装机会-日志记录,清理等。

性能方面——在许多情况下,编译器可以将多次移动优化为一次(想象一下,许多函数只是相互返回某个对象)。对于memcpy,它们的能力受到更多限制。

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