4

给定以下代码:

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 个原因(即使它避免了调用,因此避免了's 资源的src->~T()双重回收)。T

  1. U*指向U同一对象的其他成员的类型的对象成员
  2. 隐藏的类成员可能需要更新(例如,vtable)
  3. 系统需要T记录在srcTdst

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

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

我想我已经开发了一个“对象重定位语义”,但如果其中有一个明显的漏洞,我不想让人们考虑它。

4

2 回答 2

6

“可简单复制”的概念意味着 memcpy 是安全的。您可以通过std.

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

“move-and-destroy-source”的概念已经在 C++1z 标准化过程中提出,独立于“trivially copyable”的概念。它是为异常安全而提出的;有些类型的 move-construct 不是异常安全的,但 move-construct-and-destroy-source 可以。并且存在涉及异常和容器分配的棘手问题,这使得 noexcept move-ctor 操作非常有价值。

如果这进入标准,那么如果证明有价值,也可以在标准中添加一个可简单复制的如果你不销毁源的概念。

它不适用于移动语义可以增强的所有内容,并且可能需要程序员方面的努力(编译器如何计算出“可以忽略破坏者”并不容易;所有这些都不是微不足道的图灵机行为的非结构属性是难以处理的。)

于 2015-09-02T12:45:14.467 回答
2

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

性能方面 - 在许多情况下,编译器可以将许多移动优化为一个(想象许多函数只是从彼此返回某个对象)。他们的memcpy能力受到了更多的限制。

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

于 2015-09-02T13:05:42.290 回答