假设我有任何类或结构。没有虚函数或任何东西,只是一些自定义构造函数,以及需要在析构函数中进行清理的一些指针。
对此结构使用memcpy或memmove会有什么不利影响吗?删除移动的结构会导致问题吗?问题假设内存对齐也是正确的,我们正在复制到安全内存。
答案 0 :(得分:8)
在一般情况下,是的,会有问题。 memcpy
和memmove
都是按位运算,没有进一步的语义。这可能不足以移动对象 * ,而 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确定是否可以使用memcpy
或memmove
复制或移动对象。来自文档:
普通可复制类型的对象是唯一可能的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.");
// ...
};