来自 http://en.cppreference.com/w/cpp/string/byte/memcpy :
If the objects are not TriviallyCopyable (e.g. scalars, arrays, C-compatible structs), the behavior is undefined.
在我的工作中,我们长期使用 std::memcpy
来按位交换不是 TriviallyCopyable 的对象:
void swapMemory(Entity* ePtr1, Entity* ePtr2)
{
static const int size = sizeof(Entity);
char swapBuffer[size];
memcpy(swapBuffer, ePtr1, size);
memcpy(ePtr1, ePtr2, size);
memcpy(ePtr2, swapBuffer, size);
}
从来没有任何问题。
我了解使用非 TriviallyCopyable 对象滥用 std::memcpy
并导致下游未定义行为是微不足道的。但是,我的问题:
为什么 std::memcpy
本身的行为在与非 TriviallyCopyable 对象一起使用时会未定义?为什么标准认为有必要指定?
更新
http://en.cppreference.com/w/cpp/string/byte/memcpy 的内容已根据此帖子和帖子的答案进行了修改。目前的描述是:
If the objects are not TriviallyCopyable (e.g. scalars, arrays, C-compatible structs), the behavior is undefined unless the program does not depend on the effects of the destructor of the target object (which is not run by
memcpy
) and the lifetime of the target object (which is ended, but not started bymemcpy
) is started by some other means, such as placement-new.
附言
@Cubbi 的评论:
@RSahu if something guarantees UB downstream, it renders the entire program undefined. But I agree that it appears to be possible to skirt around UB in this case and modified cppreference accordingly.
最佳答案
Why would the behavior of
std::memcpy
itself be undefined when used with non-TriviallyCopyable objects?
不是!但是,一旦您将一个不可复制类型的对象的底层字节复制到该类型的另一个对象中,目标对象就不再存在。我们通过重用它的存储来销毁它,并没有通过构造函数调用来恢复它。
使用目标对象——调用它的成员函数,访问它的数据成员——显然是未定义的[basic.life]/6,随后的隐式析构函数调用也是如此[basic .life]/4 用于具有自动存储持续时间的目标对象。请注意未定义的行为是如何追溯的。 [intro.execution]/5:
However, if any such execution contains an undefined operation, this International Standard places no requirement on the implementation executing that program with that input (not even with regard to operations preceding the first undefined operation).
如果一个实现发现一个对象是如何死亡的并且必然受到未定义的进一步操作的影响,......它可能会通过改变你的程序语义来使用react。从 memcpy
调用开始。一旦我们想到优化器和他们做出的某些假设,这种考虑就会变得非常实用。
应该注意的是,标准库能够并且允许优化某些标准库算法以用于一般可复制的类型。 std::copy
在指向普通可复制类型的指针上通常会在底层字节上调用 memcpy
。 swap
也是如此。
因此,只需坚持使用普通的泛型算法并让编译器进行任何适当的低级优化 - 这就是最初发明可复制类型的想法的部分原因:确定某些优化的合法性。此外,这避免了担心语言中矛盾和未指定的部分而伤害您的大脑。
关于c++ - 为什么 std::memcpy 的行为对于不是 TriviallyCopyable 的对象是未定义的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29777492/