C++类不可移动二进制的例子 有人知道没有二进制可动的C++类吗?

C++类不可移动二进制的例子 有人知道没有二进制可动的C++类吗?,c++,C++,换句话说,您知道有哪个类会导致内存泄漏或未定义的行为吗 { // New scope // Allocate some memory unsigned char data1[sizeof(MyClass)]; unsigned char data2[sizeof(MyClass)]; // Create an instance of the class ::new (data1) MyClass(); // Create a pointer and run some class-specific

换句话说,您知道有哪个类会导致内存泄漏或未定义的行为吗

{ // New scope
// Allocate some memory
unsigned char data1[sizeof(MyClass)];
unsigned char data2[sizeof(MyClass)];
// Create an instance of the class
::new (data1) MyClass();
// Create a pointer and run some class-specific code
MyClass* ptr = (MyClass*) data1;
ptr->MyFunction();
// Binary move everything to data2
::memcpy((void*)data2, (void*)data1, sizeof(MyClass));
::memset((void*)data1, sizeof(MyClass), 0); // for clarification
// Run some code at the new memory location, same object
ptr = (MyClass*) data2;
ptr->MyFunction();
// Run destructor at memory location2
(&*data2)->~MyClass(); 
} // ... out of scope. No implicit destructors called. No memory leaks.
更新:

我所说的二进制可移动是指任何可以被二进制移动到内存中另一个位置并仍能正常工作的对象。move构造函数可以用memcpy实现

当然,任何有指向它们的指针的物体都不能移动,这不是问题的一部分

阐明tr1::smart_ptr、std::deque、std::vector和std::list等类可以是二进制可移动的,所以在重新分配节点时,不要为它们的内部行为争论不休

clarify处理内存分配的类可以是二进制移动的,因为二进制移动意味着在移动后不会同时处理两个对象,并且析构函数不会被调用两次


如果任何其他对象存储指向您的对象的指针,则您的对象不再是二进制可移动的(也称为按位可移动的)。双链表元素就是一个很好的例子。如果要重新定位双链接列表中的元素,则需要调整相邻元素中的指针。因此,如果您尝试仅使用memmove来重新定位元素,列表将中断。

我认为您很难知道类实例的确切大小,特别是考虑到虚拟方法。

任何流类*都将有一个内部缓冲区,以及指向该缓冲区内下一个字符的指针。它们不会是可移动的

*流类的本质:一次提供对某些连续数据流、一部分字符、int、字符串等的访问。几乎总是通过一次从数据源(例如文件)读取一个大数据块,然后用指针遍历它来实现

我使用offset_ptr类型来构建 内存blob中的结构,我 要在内存中进行交换吗 到磁盘或网络,或与一起使用 共享内存。偏移量存储 对象位置t作为 这个和t之间的距离。在里面 要复制偏移指针,请执行以下操作: 必须调整内部偏移, 因此,只有当 对象,它指向它移动的对象 与实际情况相同的金额 对于上述内存块

使用对象是很常见的 位置作为访问 相关资源,特别是在 ressource经常不被使用 而且会增加相当大的开销 如果聚合到对象本身。 例如,如果您想要每个对象 要拥有可选的互斥锁,您可以 要组成一个全局哈希表吗 映射对象位置的位置 这是它的关联互斥体, 当然,只有当 实际要求的。你不能移动这样的东西 显然,我不再反对了


智能指针、容器和其他资源管理类(其析构函数负责释放资源)必须在移动时失效。否则,旧对象将释放本应转移到新对象的资源


更新:这是对原始问题的回答,后来被更改为使其无效。

一个使用原始内存以避免过早构造的类:

template <class T, size_t N>
class aligned_storage
{
public:
private:
  T* mHead;
  unsigned char mData[N*sizeof(T) + std::tr1::alignment_of<T>::value - 1];
};
这里的问题有两个方面:

mHead指向对象本身,因此它当然应该被更改 即使我们对偏移量使用了某种字节计数,移动后也必须更改此偏移量。 当然,任何使用订阅机制观察者模式的类,因为您需要从复制的对象取消订阅,并从新对象订阅


在移动构造函数中使用按位复制与在复制构造函数中使用按位复制没有太大区别。。。当你处理非POD时,这是一个坏主意。

一些保存可变长度数据的类具有分配函数,在连续块中分配sizeofClass+ExtraDataSize,然后使用placement new在该空间中创建对象。在这样的方案中,类不需要有指向额外数据的成员指针,因为它将位于unsigned char*this+sizeof*this


显然,这样的类不会有公共副本。理论上,你可以二进制移动它,但是分配器只返回一个类*,你不知道需要移动多少字节。

< P>什么是C++对象难以移动,而不是单独的对象在复制时停止在自己的工作中工作。这个问题涉及相对较小的对象类,例如包含指向自身的指针的对象或在某种循环引用集中紧密工作的对象

C++对象很难移动,因为:

他们被指向了!这是第一个问题。除非找到某种方法来确保在移动所有指向将来可能使用的对象的指针后,这些指针都会被更新,否则根本没有必要考虑移动对象。C++,根据定义,几乎不可能。

在运行时很难确定任何给定对象的实际类和大小。如何创建任何一般的移动过程,如果你不能确定对象是什么类,没有它,你就不能更新嵌入指针,如果需要的话,它真的开始思考:虚拟继承和它是什么大小,你想说什么,但是在最后有可变大小的缓冲区的优秀的旧C结构是有效的C++对象;C数组也是如此

因未回答其问题而被OP否决后更新

确切问题的确切答案:

有人知道没有二进制可动的C++类吗? 对

<>每个C++类不是二进制可移动的,而是由问题中定义的。 这很合乎逻辑

每个C++类的实例都可以指向指针。 这个类的作者无法阻止它。 此外,在某个时间点,每个类实例肯定都有一个指向它的指针。 所以没有C++类可以满足条件2: 任何具有指向它们的指针的对象都不能移动。 因此,没有C++类可以通过这个定义二进制移动。 换句话说,您知道有哪个类会导致内存泄漏或未定义的行为吗?[下面是源代码片段]

忽略问题2不是问题1这一事实,换句话说。 甚至不接近。相反,我将回答问题2,因为它本身

对。很多

已经提供了几个例子

更多示例:

链表实现为循环双链表,哨兵节点作为成员嵌入链表类对象本身。 执行此代码-假设第一个ptr->MyFunction;创建至少一个节点-当循环删除节点到达旧sentinel节点的位置(现在为零)时,将导致未定义的行为

表单as-in-GUI元素包含一些控件,这些控件带有指向它们作为成员的指针,并侦听它们的事件。 如果第二个ptr->MyFunction;允许触发事件,例如,通过执行某种形式的Form::Show方法,当事件处理程序试图通过已归零的指针操纵控件时,将导致未定义的行为

例如,如果类的sizeof==13,精确的值并不重要,它的第一个成员需要在4字节边界上对齐,例如,它是一个虚拟函数表指针,那么它是一个未定义的行为,因为data2的对齐不符合类的要求。在某些平台上,这并不重要。另一方面,它的运行速度会慢得多。在其他方面,它将崩溃


你说的二进制可移动是什么意思?@Neil Butterworth:他很可能是指不能使用memmove更改内存中的对象位置。你可以阅读关于默认移动函数的建议:。它们唤起了可移动对象中的指针和引用的问题。-1 a不仅忽略了房间里的大象,还因为简单地提到了大象而否决了任何人,b提出问题只是为了得到具体的答案:不,没有C++类,它不是二进制可移动的,然后改变问题和二进制可移动的定义,直到你得到这个答案。@维克多:这就是为什么你得到了下注:你坚持,即使标准很清楚,1只覆盖POD对象,而std::list绝对不是一个POD。sizeof有什么难的?@Rob:sizeof只有在你知道动态类型的情况下才有效。如果你只是得到一个基类的引用,那么你就无法找出整个对象的大小。问题是关于不可移动的类。虽然这是一个无法移动对象的情况,但这是因为您不知道其类,而不是因为类本身的属性。类似地,如果任何对象具有指向类实例的任何成员变量的指针,则表示该对象不能按位移动。不要对此进行投票。链接列表和双链接列表都是二进制可移动的,因为在二进制移动实际类时,它们的元素可以保持固定。@Viktor:如果列表是侵入性的,即链接嵌入元素而不是包装器中,那么简单地移动元素将断开链接,正如sharptooth所说。如果链表对象本身有一个或多个节点的空间,即当它使用类似于小字符串优化的优化时,也不起作用。@Viktor:堆栈与任何东西有什么关系?如果你问你想要回答的问题,你可能会得到更好的回答,而不是在别人看不懂你的心思时抱怨。假设我们正在做一个真实的移动,而不是复制,那么这些对象就可以了,因为它们持有指向外部和可能未移动对象的指针。只有当指针和指向的对象一起移动时才有问题。@James:问题是旧对象仍然认为它在管理外部资源,所以它的析构函数会在它仍然可用时释放它;然后新对象的析构函数
或者如果程序还没有崩溃,最终会尝试第二次发布。您需要使旧对象无效的移动语义,而按位复制不能做到这一点。@James:我们不是在讨论真正的移动;问题是关于如何将move实现为一个简单的memcpy。@迈克·西摩:你不需要移动语义,如果std::vector在分配更多内存而不是复制构造时实现为memcpy all elements,它仍然可以工作。@Viktor:我不知道你想回答什么问题,但我留下这个答案是因为它确实回答了您提出的问题。通过内部缓冲区,您指的是对象内部的数组?否则它的二进制可移动+1是。假设缓冲区大小在编译时已知,因此可以将其放入对象中,而不是单独分配。