Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 安全移动C++;对象_C++_Memory Management_Pointers - Fatal编程技术网

C++ 安全移动C++;对象

C++ 安全移动C++;对象,c++,memory-management,pointers,C++,Memory Management,Pointers,我听到一些警告,不要通过memcpy将对象发送到另一个内存位置,但我不知道具体原因。除非它包含的成员根据内存位置做一些棘手的事情,否则这应该是完全安全的…还是不安全 编辑:预期的用例是一种数据结构,如向量,它将对象(而不是指向对象的指针)存储在连续的内存块(即数组)中。要在第n个位置插入一个新对象,从第n个位置开始的所有对象都需要移动,以便为要插入的对象腾出空间。从我的头顶开始:如果你只是做一个memcpy,那么你最终会做一个浅拷贝。如果你需要一份深度拷贝,那么这就行不通了 复制构造函数和赋值运

我听到一些警告,不要通过
memcpy
将对象发送到另一个内存位置,但我不知道具体原因。除非它包含的成员根据内存位置做一些棘手的事情,否则这应该是完全安全的…还是不安全


编辑:预期的用例是一种数据结构,如
向量
,它将对象(而不是指向对象的指针)存储在连续的内存块(即数组)中。要在第n个位置插入一个新对象,从第n个位置开始的所有对象都需要移动,以便为要插入的对象腾出空间。

从我的头顶开始:如果你只是做一个memcpy,那么你最终会做一个浅拷贝。如果你需要一份深度拷贝,那么这就行不通了


复制构造函数和赋值运算符到底有什么问题?

不应该这样做的一个主要原因是析构函数。当将C++对象MimcPy移动到内存中的另一个位置时,最终将有2个版本的内存对象,其中只有1个构造函数已经运行。这将破坏几乎所有的C++类的资源释放逻辑。p> 如果对象中没有指针,也没有虚函数,也没有具有相同指针的子对象,那么您可能会侥幸逃脱。这是不推荐的

这应该使用copy或deepcopy函数或重写的运算符来完成

在该方法中,您将调用一个新的构造函数并逐个复制它包含的数据项

对于浅复制,您将复制指针/引用,这样您将有两个对象指向相同的包含元素。。。。一个潜在的内存泄漏噩梦

对于深度副本,您将遍历包含的对象和引用,并创建它们的新副本


要移动对象,您需要复制它并删除原始对象。

语言规范不允许这样做。这是未定义的行为。归根结底,这就是问题所在。在实践中,它往往会弄乱虚拟函数调用,这意味着析构函数将运行两次(并且比构造函数更频繁),成员对象是浅拷贝的(因此,例如,如果您使用
std::vector
尝试此特技,它会爆炸,因为多个对象最终指向同一个内部数组。)


吊舱类型是个例外。它们没有(复制)构造函数、析构函数、虚拟函数、基类或任何其他可能导致此中断的东西,因此,您可以使用memcpy来复制它们。

简短回答:
std::memcpy()
用于移动内存,而不是移动对象。尽管如此,使用它仍将调用未定义的行为

稍长的回答:不是POD的C++对象可能包含需要释放的资源,这些资源保存在无法复制的句柄中。(一种流行的资源是内存,其中句柄是指针。)它还可能包含由实现插入的内容(虚拟基类实例指针),这些内容不应该像复制内存一样进行复制


在C++98和C++03中移动对象的唯一正确方法是将其复制到新位置并调用旧位置中的析构函数。(在C++1x中,会有移动语义,因此在某些情况下事情可能会变得更有趣。)

为了便于讨论,我假设您的意思是移动意味着原始对象“已删除”(不再使用,没有运行析构函数),而不是有两个副本(这将导致更多的问题,引用计数被关闭,等等)。我通常指的是能够做到这一点的属性是按位移动的

在我所研究的代码库中,大多数对象都是按位移动的,因为它们不存储自引用。然而,一些数据结构不是按位移动的(我相信gcc的std::set不是按位移动的;其他示例可能是)。通常,我会避免尝试使用此属性,因为它可能会导致一些很难调试的错误,我更喜欢使用面向对象的调用复制构造函数

编辑以添加

关于某人如何/为什么会这样做,似乎存在一些困惑:以下是我对如何这样做的评论:

通常情况下,我会在备用屏幕上看到上述内容 向量的实现。内存 是通过 malloc(尺寸(等级)*尺寸)和 对象通过 显式调用构造函数和 析构函数。有时(比如在 重新分配)他们必须被转移, 因此,选项是执行std::vector的 复制构造函数的重复调用 在新的内存和析构函数上 旧的,或者使用memcopy,只是“免费” 老街区。大多数时候是后者 只是“管用”,但不是全部 对象

至于原因,memcopy(or)方法可以大大加快速度

是的,它调用了未定义的行为,但是它也倾向于为大多数对象工作。有些人认为速度是值得的。如果你真的开始使用这个方法,我建议实现一个BITWISEAB可移动的类型特性,让它工作的类型是白色的,并且返回到传统的拷贝中,而不是在对象中。白名单,与示例非常相似。

通常(在所有语言中,而不仅仅是C++)为了安全地移动对象,还需要重写所有指向该对象的指针/引用,这是C++中的一个问题,因为没有简单的方法来判断系统中的任何对象是否有一个“隐藏”的指针指向您正在移动的对象。这些类可能在跟踪所有实例的工厂对象中有隐藏指针。看起来不相关的类也可能出于自身的各种原因缓存指向对象的指针

唯一安全的方法是对系统中的所有对象进行某种反射访问,以便找到所有指针