为什么不保证memcpy对非POD类型是安全的?

ROT*_*OGG 10 c++

我从SO上发布的一些问题中读到了这一段.

我无法弄清楚为什么memcpy不保证非POD类型的安全性.我的理解是,这memcpy只是一个有点明智的副本.

以下是标准报价

对于任何对象(比基类的其他子对象)的POD类型T,所述对象是否保持类型的有效的值T,构成对象的底层字节(1.7)可以被复制到的阵列charunsigned char0.41)如果阵列的内容charunsigned char将被复制回对象,该对象随后应保持其原始值.

# define N sizeof (T)
char buf[N];
T obj ; // obj initialized to its original value
std :: memcpy (buf , & obj , N); // between these two calls to std::memcpy,
                                 // obj might be modified
std :: memcpy (& obj , buf , N); // at this point, each subobject of obj of 
                                 // scalar type holds its original value
Run Code Online (Sandbox Code Playgroud)

Mar*_*tos 17

尝试按位复制std::shared_ptr<>.您可能会发现您的程序经常在您的脸上爆炸.

你会遇到任何类的副本构造函数执行除了按位复制之外的其他类的问题.在的情况下std::shared_ptr<>,它会复制指针,但不会增加引用计数,所以你最终会释放共享对象和它的引用计数早期,然后吹起来的时候复制shared_ptr试图减小释放的引用计数.


更新:有人指出,这并不完全回答这个问题,这是公平的,因为我主要是针对复制的shared_ptr的想法到shared_ptr,shared_ptr不为char [],然后再返回.但是,原则仍然存在.

如果逐位一个shared_ptr复制到一个char [],分配不同的值给shared_ptr的,然后复制的char []回过来,最终结果可能是泄漏一个对象和双删除另一个,即UB.

POD可能会发生同样的情况,但这可能是程序逻辑中的一个错误.只要程序理解并适应这样的事件,逐位复制回POD等效于修改后的shared_ptr就完全有效.对std :: shared_ptr这样做通常不起作用.


nio*_*nio 6

想象一个类,它包含一些指向缓冲区的指针,如下所示:

class Abc {
    public:
    int* data;
    size_t n;
    Abc(size_t n)
    {
        this->n = n;
        data = new int[n];
    }

    // copy constructor:
    Abc(const Abc& copy_from_me)
    {
        n = copy_from_me.n;
        data = new int[n];
        memcpy(data, copy_from_me.data, n*sizeof(int));
    }
    Abc& operator=(const Abc& copy_from_me)
    {
        n = copy_from_me.n;
        data = new int[n];
        memcpy(data, copy_from_me.data, n*sizeof(int));
        return *this;
    }

    ~Abc()
    {
        delete[] data;
    }
} ;
Run Code Online (Sandbox Code Playgroud)

如果只记忆其构建的实例之一,则会得到两个指向同一缓冲区的实例data,因为它们在data指针中具有相同的缓冲区地址.如果您在一个实例中修改数据,它也将在另一个实例中进行修改.

这意味着你没有真正将它克隆到两个独立的类中.此外,如果然后删除这两个类,缓冲区将从崩溃的内存中释放两次.因此,类必须定义一个复制构造函数,您必须使用构造函数复制它.

  • @Dariusz:只是因为某个东西是结构,不会成为POD.我认为帖子试图制作的重点与三条规则相同:dtor可以尝试删除数据指向的内存,当memcpyd导致双重删除时,复制ctor解决了做一个深刻的副本. (5认同)
  • 这个新例子并没有好多少.无论你是memcpy,还是像`Abc y = x;`这样的常规副本,它都会破坏.它没有记忆它被打破,它是类本身.当然破坏了代码. (5认同)
  • 这实际上没有任何证据.包含指针的struct也会发生同样的情况,struct是POD类型. (2认同)
  • @Dariusz在C++中,`struct`就像`class`,唯一的区别是`struct`默认为`public`和`class`为`private`. (2认同)