简体   繁体   English

关于移动活动对象存储,C ++标准怎么说?

[英]What does C++ standard say about moving live object storage?

I am curious about how the following situation is interpreted under current C++ standard, especially in respect to lifetimes etc. Is it undefined behaviour? 我对在当前的C ++标准下如何解释以下情况感到好奇,尤其是在生命周期等方面。它是未定义的行为吗?

First, lets start with the following definition: a relocatable object is an object which is invariant on its actual memory location — that is, its state stays the same regardless of the value of the pointer this. 首先,让我们从以下定义开始:可重定位对象是在其实际存储位置上不变的对象-也就是说,无论指针this的值如何,其状态都保持不变。 Assume that we have a relocatable type Relocatable (its definition is irrelevant for the example). 假设我们有一个可重定位的类型Relocatable(它的定义与示例无关)。

Then we have the following code (C++17): 然后我们有以下代码(C ++ 17):

typedef std::aligned_storage_t<sizeof(Relocatable)> Storage;

// construct an instance of a relocatable within a storage
auto storage0 = new Storage();
new(storage0) Relocatable(...);

{ 
  // obj is a valid reference
  // should use std::launder() here, but clang doesn't have it yet
  Relocatable& obj = *reinterpret_cast<Relocatable*>(storage0);
}

// move the storage
auto storage1 = new Storage();
memcpy(storage1, storage0, sizeof(Storage));
delete storage0;

{ 
  // ?????? what does the standard say about this?
  Relocatable& obj = *reinterpret_cast<Relocatable*>(storage1);
}

This works with both GCC and Clang as expected (the object simply continues to exist in the new storage). 它可以按预期与GCC和Clang一起使用(对象只是继续存在于新存储中)。 However, I am not entirely sure whether the standard is ok with this. 但是,我不能完全确定该标准是否可行。 Technically, the lifetime of the object has not ended (destructor has been not called) and there hasn't been any access to the object in the old location after the memcpy() call. 从技术上讲,对象的生存期尚未结束(未调用析构函数),并且在memcpy()调用之后,没有任何访问该对象的旧位置。 Also, there exist no references/pointers to the old location. 另外,不存在对旧位置的引用/指针。 Still, given that C++ seems to treat object identity and object storage as the same thing most of the time, there might be a reason why this is prohibited. 尽管如此,鉴于C ++在大多数情况下似乎将对象标识和对象存储视为相同的事物,因此可能有理由禁止这样做。 Thanks in advance for all the insightful comments. 在此先感谢您提出的所有深刻见解。

Edit: It has been suggested that Why would the behavior of std::memcpy be undefined for objects that are not TriviallyCopyable? 编辑:有人建议为什么对于不是TriviallyCopyable的对象,std :: memcpy的行为将是未定义的? is a duplicate of this questions. 是这个问题的重复。 I am not sure it is. 我不确定。 First of all, I am memcpying the storage, not the object instance. 首先,我正在存储,而不是对象实例。 Second, std::is_trivially_copyable<Relocatable>::value actually evaluates to true for all practically relevant applications. 其次,对于所有实际相关的应用程序, std::is_trivially_copyable<Relocatable>::value实际评估为true

PS There is actually a good practical reason why I am asking this. 附言:我问这个问题实际上有一个很好的实际原因。 Sometimes it is useful to have objects which can only exist within their container — they are not copyable and not moveable. 有时,使对象只能存在于其容器中很有用-它们是不可复制且不可移动的。 For instance, I am currently designing an optimized tree data structure with such a properties — tree nodes can only exist within the tree storage, they can't be moved out or copied — all operations on them are carried out via short-lived references. 例如,我目前正在设计具有此类属性的优化树数据结构-树节点只能存在于树存储中,不能移出或复制它们-对它们的所有操作都是通过短期引用来执行的。 To prevent programmer mistakes (accidental copies/moves), I am deleting both the copy and the move constructor. 为了防止程序员犯错误(意外的复制/移动),我同时删除了复制和move构造函数。 Which has the rather unfortunate consequence that the nodes can't be stored within a std::vector. 不幸的结果是无法将节点存储在std :: vector中。 Placement new and explicitly managed storage can be used to bypass this limitation — but of course I wouldn't want to do something that is not ok according to the standard. 可以使用放置新的显式管理的存储来绕过此限制-但是,根据标准,我当然不愿意做某些不可行的事情。

So, as with all of these kinds of questions, objects are only created in four situations : 因此,与所有这些类型的问题一样,仅在四种情况下创建对象:

An object is created by a definition ([basic.def]), by a new-expression , when implicitly changing the active member of a union ([class.union]), or when a temporary object is created ([conv.rval], [class.temporary]). 当隐式更改联合的活动成员([class.union])或创建临时对象([conv.rval)时,将通过定义([basic.def]), new-expression创建对象。 ],[class.temporary])。

This code: 这段代码:

auto storage1 = new Storage();
memcpy(storage1, storage0, sizeof(Storage));

Gives you an object of type Storage at storage1 , but there is no object of type Relocatable ever created at that point. storage1给您一个类型为Storage的对象,但是那时还没有创建Relocatable类型的对象。 Hence, this: 因此,这:

Relocatable& obj = *reinterpret_cast<Relocatable*>(storage1);

is undefined behavior. 是未定义的行为。 Period. 期。


In order to define behavior for that, we need a fifth mechanism to create an object, such as what is proposed in P0593 : 为了为此定义行为,我们需要第五种机制来创建对象,例如P0593中提出的内容

We propose that at minimum the following operations be specified as implicitly creating objects: [...] 我们建议至少将以下操作指定为隐式创建对象:[...]

  • A call to memmove behaves as if it 调用memmove行为就像

    1. copies the source storage to a temporary area 将源存储复制到临时区域

    2. implicitly creates objects in the destination storage, and then 在目标存储中隐式创建对象,然后

    3. copies the temporary storage to the destination storage. 将临时存储复制到目标存储。

    This permits memmove to preserve the types of trivially-copyable objects, or to be used to reinterpret a byte representation of one object as that of another object. 这允许memmove保留普通复制对象的类型,或用于将一个对象的字节表示重新解释为另一对象的字节表示。

  • A call to memcpy behaves the same as a call to memmove except that it introduces an overlap restriction between the source and destination. 调用memcpy行为与调用memmove行为相同,不同之处在于它在源和目标之间引入了重叠限制。

This proposal (or something like it) would be necessary your code well-formed. 该建议(或类似的建议)对于格式正确的代码很有必要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C++ 标准对堆栈溢出有何规定? - What does the C++ standard say about stack overflow? C ++语言标准对static_cast如何处理减小整数大小有何看法? - What does the C++ language standard say about how static_cast handles reducing the size of an integer? 关于使用noexcept覆盖throw()函数,C ++标准有何说法? - What does the C++ standard say about overriding a throw() function with noexcept? C ++标准对于在目标类型范围之外的类型的转换结果的结果有何评价? - What does the C++ standard say about results of casting value of a type that lies outside the range of the target type? 数字和字段宽度的格式化输出,C ++标准对此有何说明? - formatted output of a number and field width, where does the C++ standard say about it? 说 C++ 对象是可移动的到底是什么意思? - What exactly does it mean to say a C++ object is movable? C++20 标准对使用子对象作为模板非类型 arguments 有什么看法? - What does the C++20 standard say about usage of subojects as template non-type arguments? C ++标准对std :: vector的评价是什么 <int> V1,V2; 性病::距离(v1.begin(),v2.begin())? - What does the C++ standard say about std::vector<int> v1,v2; std::distance(v1.begin(),v2.begin())? 标准对未对齐的内存访问有何看法? - What does the standard say about unaligned memory access? 标准对lambda类型的命名空间有何看法? - What does the Standard say about the namespace of lambda types?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM