为什么对于不能TriviallyCopyable的对象,std :: memcpy的行为将无法定义?

来自http://en.cppreference.com/w/cpp/string/byte/memcpy:


如果对象不是TriviallyCopyable(例如标量,数组,C兼容结构),则该行为是不确定的。


在我的工作中,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);

}

从来没有任何问题。


我了解滥用std::memcpy非TriviallyCopyable对象并导致下游未定义行为是微不足道的。但是,我的问题是:


std::memcpy与非TriviallyCopyable对象一起使用时,为什么自身的行为不确定?为什么标准认为有必要对此加以说明?


更新


针对此帖子和该帖子的答案,已修改了http://en.cppreference.com/w/cpp/string/byte/memcpy的内容。当前的描述是:


如果对象不是TriviallyCopyable(例如标量,数组,与C兼容的结构),则除非程序不依赖于目标对象的析构函数的影响(不是由memcpy)运行,否则行为是不确定的。目标对象(以结束,但未以开头memcpy)是通过其他某种方式(例如,新放置)来启动的。




慕桂英3389331
浏览 405回答 3
3回答

湖上湖

构造一个memcpy基于该类swap中断的类很容易:struct X {    int x;    int* px; // invariant: always points to x    X() : x(), px(&x) {}    X(X const& b) : x(b.x), px(&x) {}    X& operator=(X const& b) { x = b.x; return *this; }};memcpy这样的对象破坏了不变性。GNU C ++ 11 std::string正是使用短字符串来做到这一点。这类似于标准文件和字符串流的实现方式。最终从中获得流,std::basic_ios其中包含指向的指针std::basic_streambuf。流还包含作为该指针指向的成员(或基类子对象)的特定缓冲区std::basic_ios。

慕丝7291255

因为标准是这样说的。编译器可能会假定非TriviallyCopyable类型仅通过其复制/移动构造函数/赋值运算符进行复制。这可能是出于优化目的(如果某些数据是私有的,则可以将其设置推迟到复制/移动发生之前)。编译器甚至可以自由地接听您的memcpy电话,使其无所事事,或格式化硬盘。为什么?因为标准是这样说的。而且无所事事肯定比移动位快得多,那么为什么不优化您的程序memcpy来使它同样有效呢?现在,在实践中,当您只对不需要的类型的位进行四处查找时,可能会发生许多问题。虚拟功能表可能未正确设置。用于检测泄漏的仪器可能未正确安装。身份包括其位置的对象将完全被您的代码弄乱。真正有趣的部分是,对于编译器可复制的类型,using std::swap; swap(*ePtr1, *ePtr2);应该可以将其编译memcpy为,对于其他类型,则应定义行为。如果编译器可以证明副本只是被复制的位,则可以将其更改为memcpy。而且,如果您可以编写更优化的代码swap,则可以在相关对象的名称空间中执行。
打开App,查看更多内容
随时随地看视频慕课网APP