aligned_storage及严格别名(aligned_storage and strict al

2019-07-03 23:40发布

我目前使用aligned_storage来实现类似的boost ::可选的“可选”类型。 要做到这一点我有一个类的成员,如下所示:

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

我用放置新创建的对象,但我不存储任何地方返回的指针。 相反,我(通过布尔标志也存储在我的可选类型显然与检查,以确保对象是有效的)访问底层的类型在这样我所有的成员函数的对象:

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

我的问题是,这是否是安全的。 我的理解是,我放置新的使用改变了对象的“动态式”,只要我继续使用这种类型的访问存储器我会好起来的。 不过我不是我是否必须持有由安置新的还是我允许只投为基础类型,每当我需要访问它返回的指针清晰。 我已阅读C ++ 11标准的3.10节,但是我没有足够的standardese流利是肯定的。

如果可能的话,我会觉得更好,如果你能给参考答案标准(它帮助我在晚上睡觉:P)。

Answer 1:

ABICT您的使用是安全的。

  • 安置新型T的对象将创建开始传入地址的对象。

§5.3.4/ 10说:

一种新的表达通过的空间要求的分配的功能类型的std的第一个参数::为size_t量。 这样的说法应不低于要创建的对象的大小更小; 不是被创建的对象的大小仅当对象是一个数组它可以更大。

对于非阵列对象,分配的大小不能大于所述对象的大小,所以对象表示必须以适合于所分配的存储器的开始处开始。

放置新返回指针中传递(见第18.6.1.3/2)作为“分配”的结果,所以构造的对象的对象表示将在该地址开始。

  • static_cast<>和之间的隐式转换T*类型和void*的指针对象的指针和指向它的存储之间进行转换,如果对象是一个完整的对象。

§4.10/ 2说:

类型“指向cv T,”,其中T是一个对象类型的prvalue,可以转换为类型“指向cv空隙”的prvalue。 一“指向cv T”转换为“指向cv空隙”指向其中类型T的对象所在,因为如果对象是类型T的最派生对象(1.8)的存储位置的起始的结果[...]

这定义了隐式转换为规定转换。 此外§5.2.9[expr.static.cast / 4定义static_cast<>为显式转换,其中的隐式转换的存在是为了具有与隐式转换相同的效果:

否则,一个表达式e可以显式转换到类型T使用static_cast形式static_cast<T>(e) ,如果声明T t(e); 是良好的,对一些发明临时变量t (8.5)。 这样的显式转换的效果是一样的进行声明和初始化,然后用临时变量作为转换的结果。 [...]

对于逆static_cast<>void*T* ),§5.2.9/ 13的状态:

类型“指针CV1空隙”的prvalue可以转换为类型的“指针CV2 T,”,其中T是一个对象类型和CV2是相同的CV-资格,或更大的CV-资格比,CV1一个prvalue。 [...]类型的指针的值,以对象转换为“指向cv空隙”和背部,可能具有不同的CV-资格,应具有其原始值。

所以,如果你有一个void*指向的存储T对象(也就是指针值会导致一个的隐式转换T*的对象,那么static_cast的是一个T*将产生一个有效的指针对象。

回到你的问题,上述要点意味着,如果你有

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)的存储字节t_ ,使pvT == pvt_
  • pvt_ == static_cast<void*>(&t_)
  • static_cast<T*>(pvT) == pT
  • 一起的是产率static_cast<T*>(static_cast<void*>(&t_)) == pT


文章来源: aligned_storage and strict aliasing