将std :: memcpy用于非平凡可复制类型的对象

2 c++ types

标准定义我们可以通过以下方式使用std :: memcpy:

对于任何简单的可复制类型T,如果指向T的两个指针指向不同的T对象obj1和obj2,其中obj1和obj2都不是基类子对象,如果构成obj1的基础字节(1.7)被复制到obj2中,obj2将随后保持与obj1相同的值.

如果我们将该函数应用于非平凡可复制类型的对象,我们可能会遇到什么样的潜在问题?以下代码的工作原理就好像它适用于普通可复制类型:

#include <iostream>
#include <cstring>

using std::cout;
using std::endl;

struct X
{
    int a = 6;
    X(){ }
    X(const X&)
    {
        cout << "X()" << endl;
    }
};

X a;
X b;
int main()
{
    a.a = 10;
    std::memcpy(&b, &a, sizeof(X));
    cout << b.a << endl; //10
}
Run Code Online (Sandbox Code Playgroud)

DEMO

Tom*_*Tom 6

考虑这个程序:

#include <memory>

int main() {
    std::shared_pointer<int> x(new int);

    {
        std::shared_pointer<int> y;
        memcpy((void*)&y, (void*)&x, sizeof(x));
    }

    *x = 5;
}
Run Code Online (Sandbox Code Playgroud)

因为我们复制xyusingmemcpy而不是赋值运算符,所以引用计数没有更新。因此,在该块的末尾,y调用 的析构函数。它发现它的引用计数为1,这意味着它是唯一指向堆分配整数的shared_pointer实例。所以它删除了它。

最后一行main可能会出现段错误,因为x指向已被删除的对象。


R S*_*ahu 5

您询问:

如果我们将该函数应用于非平凡可复制类型的对象,我们可能会遇到什么样的潜在问题?

这是一个非常简单的例子,它说明了使用std::memcpy非平凡可复制类型的对象的问题.

#include <cstring>

struct A
{
   A(int size) : size_(size), data_(new int[size]) {}
   ~A() { delete [] data_; }

   // The copy constructor and the copy assignment operator need
   // to be implemented for the class too. They have been omitted
   // to keep the code here minimal.

   int size_;
   int* data_;
};

int main()
{
   A a1(10);
   A a2(20);
   std::memcpy(&a1, &a2, sizeof(A));

   // When we return from the function, the original data_ of a1
   // is a memory leak. The data_ of a2 is deleted twice.

   return 0;
}
Run Code Online (Sandbox Code Playgroud)