memcpy或memmove会导致复制类的问题吗?

时间:2012-08-27 03:00:56

标签: c++ class memcpy memmove

假设我有任何类或结构。没有虚函数或任何东西,只是一些自定义构造函数,以及需要在析构函数中进行清理的一些指针。

对此结构使用memcpy或memmove会有什么不利影响吗?删除移动的结构会导致问题吗?问题假设内存对齐也是正确的,我们正在复制到安全内存。

5 个答案:

答案 0 :(得分:8)

在一般情况下,是的,会有问题。 memcpymemmove都是按位运算,没有进一步的语义。这可能不足以移动对象 * ,而 copy 显然是不够的。

在复制的情况下,它将断开,因为多个对象将引用相同的动态分配的内存,并且多个析构函数将尝试释放它。请注意,像shared_ptr这样的解决方案在这里无济于事,因为共享所有权是memcpy / memmove不提供的进一步语义的一部分。

对于移动,并且在某些情况下,根据您可能会使用它的类型。但是如果对象保持对被移动元素的指针/引用(包括自引用),它将无法工作,因为指针将被按位复制(同样,没有复制/移动的进一步语义)和将引用旧位置。

一般答案仍然相同:


* 不要在确切的C ++ 11意义上采用 move 。我已经看到标准库容器的实现,它使用特殊标记来启用移动对象,同时通过使用memcpy来增加缓冲区,但它需要在存​​储类型中显式注释标记对象作为安全地移动通过memcpy ,在将对象放入新缓冲区之后,旧缓冲区被丢弃而不调用任何析构函数(C ++ 11 move 要求将对象保留在可破坏状态,这是通过此hack无法实现的)

答案 1 :(得分:5)

通常在基于类的对象上使用memcpy并不是一个好主意。最可能的问题是复制指针然后删除它。您应该使用复制构造函数或赋值运算符。

答案 2 :(得分:4)

不,不要这样做。

如果你memcpy一个析构函数在其自身内删除指针的结构,当结构的第二个实例以任何方式被破坏时,你最终会进行双重删除。

C ++习语是类和std::copy或其任何朋友的复制构造函数,用于复制范围/序列/容器。

答案 3 :(得分:3)

除了安全性,这是其他答案已经指出的最重要的问题,可能还存在性能问题,特别是对于小型物体。

即使对于简单的POD类型,您可能会发现在复制构造函数的初始化列表中执行正确的初始化(或根据您的用法在赋值运算符中进行赋值)实际上甚至比memcpy的内部版本更快。这很可能是由于memcpy的入口代码可能会检查字对齐,重叠,缓冲区/内存访问权限等等。在Visual C ++ 10.0及更高版本中,为了给你一个具体的例子,你会惊讶于在memcpy甚至开始其逻辑功能之前,测试各种事物执行的大量前导码。

答案 4 :(得分:3)

如果您使用的是C ++ 11,则可以使用std::is_trivially_copyable确定是否可以使用memcpymemmove复制或移动对象。来自文档:

  

普通可复制类型的对象是唯一可能的C ++对象   安全地使用std :: memcpy复制或序列化为/从二进制文件   使用std :: ofstream :: write()/ std :: ifstream :: read()。一般来说,一个   平凡的可复制类型是底层字节可以使用的任何类型   被复制到char或unsigned char数组并转换为新对象   相同类型,结果对象将具有相同的值   作为原作。

许多课程都不适合这种描述,你必须要注意课程可以改变。我建议如果您要在C ++对象上使用memcpy / memmove,那么您可以以某种方式保护不必要的使用。例如,如果您正在实现一个容器类,那么容器所容纳的类型很容易被修改,这样它就不再是可复制的(例如,某人添加了一个虚函数)。您可以使用static_assert

执行此操作
template<typename T>
class MemcopyableArray
{
    static_assert(std::is_trivially_copyable<T>::value, "MemcopyableArray used with object type that is not trivially copyable.");
    // ...
};