aligned_storage和严格的别名 [英] aligned_storage and strict aliasing

查看:105
本文介绍了aligned_storage和严格的别名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用aligned_storage来实现类似于boost :: optional的可选"类型.为此,我有一个像这样的班级成员:

I'm currently using aligned_storage to implement an 'Optional' type similar to that of boost::optional. To accomplish this I have a class member like so:

typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type t_;

我使用new放置来创建对象,但是我不将返回的指针存储在任何地方.相反,我在这样的所有成员函数中访问对象的基础类型(显然,通过也存储在我的Optional类型中的布尔标志进行检查以确保对象有效):

I use placement new to create the object, however I don't store the pointer returned anywhere. Instead, I access the underlying type of the object in all my member functions like this (obviously with checks to ensure the object is valid via a boolean flag also stored in my Optional type):

T const* operator->() const {
    return static_cast<T const*>(static_cast<void const*>(&t_));
}

我的问题是,这是否安全.我的理解是,我使用new放置会更改对象的动态类型",只要我继续使用该类型访问内存,我就可以了.但是,我不清楚是必须保留从new放置位置返回的指针,还是在需要访问它时是否只允许将其强制转换为基础类型.我已经阅读了C ++ 11标准的3.10节,但是我不太会说流利的标准语言.

My question is whether this is safe. My understanding is that my usage of placement new changes the 'dynamic type' of the object, and as long as I keep accessing the memory using that type I'll be okay. However I'm not clear on whether I have to hold the pointer returned from the placement new or whether I'm allowed to just cast to the underlying type whenever I need to access it. I have read section 3.10 of the C++11 standard, however I'm not fluent enough in standardese to be sure.

如果可能的话,如果您能在答案中引用标准,会更好一些(它可以帮助我在晚上睡觉:P).

If possible, I would feel better if you could give reference to the standard in your answer (it helps me sleep at night :P).

推荐答案

ABICT您的使用是安全的.

ABICT your use is safe.

  • 将类型为T的对象放置到新位置将创建一个从传入地址开始的对象.

§5.3.4/10说:

§5.3.4/10 says:

new表达式将请求的空间量传递给 分配函数作为类型std :: size_t的第一个参数.那 参数应不小于正在创建的对象的大小; 仅当以下情况时,它才可能大于所创建对象的大小: 该对象是一个数组.

A new-expression passes the amount of space requested to the allocation function as the first argument of type std::size_t. That argument shall be no less than the size of the object being created; it may be greater than the size of the object being created only if the object is an array.

对于非数组对象,分配的大小不能大于对象的大小,因此,对象表示必须从分配的内存的开头开始以适应.

For a non-array object, the size allocated cannot be greater that the size of the object, so the object representation must start at the beginning of the allocated memory in order to fit.

placement new返回作为分配"结果传入的指针(请参见第18.6.1.3/2节),因此,构造对象的对象表示形式将从该地址开始.

Placement new returns the pointer passed in (see § 18.6.1.3/2) as the result of the "allocation", so the object representation of the constructed object will start at that address.

  • static_cast<>T*类型与void*之间的隐式转换在指向对象的指针和指向对象存储的指针之间进行转换(如果对象是完整的对象).
  • static_cast<> and implicit conversions between T* type and void* convert between a pointer to the object and a pointer to its storage, if the object is a complete object.

§4.10/2说:

类型为"cv T的指针"的prvalue(其中T是对象类型)可以是 转换为类型为"cv void的指针"的prvalue.的结果 将"pointer to cv T"转换为"pointer to cv void"指向 T类型对象所在的存储位置的开始,例如 如果对象是类型T [...]

A prvalue of type "pointer to cv T," where T is an object type, can be converted to a prvalue of type "pointer to cv void". The result of converting a "pointer to cv T" to a "pointer to cv void" points to the start of the storage location where the object of type T resides, as if the object is a most derived object (1.8) of type T [...]

这定义了隐式转换以按规定进行转换.进一步的§5.2.9[expr.static.cast]/4为显式转换定义了static_cast<>,其中隐式转换的存在与隐式转换具有相同的作用:

This defines the implicit conversion to convert as stated. Further §5.2.9[expr.static.cast]/4 defines static_cast<> for explicit conversions, where an implicit conversion exists to have the same effect as the implicit conversion:

否则,可以将表达式e显式转换为类型T 如果声明,则使用格式为static_cast<T>(e)static_cast T t(e);的格式正确,适用于某些发明的临时变量t(8.5). 这种显式转换的效果与执行 声明和初始化,然后使用临时 转换后的结果变量. [...]

Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. [...]

对于倒数static_cast<>(从void*T*),第5.2.9/13节指出:

For the inverse static_cast<> (from void* to T*), §5.2.9/13 states:

指针指向cv1无效"类型的prvalue可以转换为prvalue 类型为指向cv2 T的指针",其中T是对象类型,而cv2是 与cv1相同或更高的cv资格. [...] 指向对象的类型指针的值转换为"cv void的指针" 背面,可能具有不同的cv资格,应具有 原始值.

A prvalue of type "pointer to cv1 void" can be converted to a prvalue of type "pointer to cv2 T," where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. [...] A value of type pointer to object converted to "pointer to cv void" and back, possibly with different cv-qualification, shall have its original value.

因此,如果您有一个void*指向T对象的存储(这是将T*隐式转换为对象的指针值,则该static_cast T*会产生指向该对象的有效指针.

So if you have a void* pointing to the storage of the T object (which is the pointer value that would result from the implicit conversion of a T* to the object, then a static_cast of that to a T* will produce a valid pointer to the object.

回到您的问题,以上几点暗示,如果您有

Returning to your question, the preceding points imply that if you have

typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type t_;
void * pvt_ = &t_;

T* pT = new (&t_) T(args...);
void * pvT = pT;

然后

  • *pT的存储与t_的存储的第一个size(T)字节完全重叠,因此pvT == pvt_
  • pvt_ == static_cast<void*>(&t_)
  • static_cast<T*>(pvT) == pT
  • 放在一起产生static_cast<T*>(static_cast<void*>(&t_)) == pT
  • the storage of *pT exactly overlays the first size(T) bytes of the storage of t_, so that pvT == pvt_
  • pvt_ == static_cast<void*>(&t_)
  • static_cast<T*>(pvT) == pT
  • Taken together that yields static_cast<T*>(static_cast<void*>(&t_)) == pT

这篇关于aligned_storage和严格的别名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆