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

时间:2014-09-25 05:02:10

标签: 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
}

DEMO

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:1)

考虑这个程序:

#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;
}

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

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