ABICT 您的使用是安全的。
- 类型 T 的对象的放置 new 将创建一个从传入的地址开始的对象。
§5.3.4/10 说:
new 表达式将请求的空间量作为 std::size_t 类型的第一个参数传递给分配函数。该参数不应小于正在创建的对象的大小;只有当对象是一个数组时,它才可能大于正在创建的对象的大小。
对于非数组对象,分配的大小不能大于对象的大小,因此对象表示必须从分配内存的开头开始才能适合。
Placement new 返回传入的指针(参见第 18.6.1.3/2 节)作为“分配”的结果,因此构造对象的对象表示将从该地址开始。
static_cast<>
T*
如果对象是完整对象,则类型之间的隐式转换以及void*
指向对象的指针和指向其存储的指针之间的转换。
§4.10/2 说:
“指向 cv T 的指针”类型的纯右值,其中 T 是对象类型,可以转换为“指向 cv void 的指针”类型的纯右值。将“指向 cv T 的指针”转换为“指向 cv void 的指针”的结果指向类型 T 的对象所在的存储位置的开始,就好像该对象是类型 T 的最派生对象 (1.8) [...]
这将隐式转换定义为按说明进行转换。进一步的 §5.2.9[expr.static.cast]/4 定义static_cast<>
了显式转换,其中存在隐式转换与隐式转换具有相同的效果:
否则,对于某些发明的临时变量(8.5) ,如果声明
格式正确,则表达式e
可以T
使用static_cast
形式的 a 显式转换为类型。这种显式转换的效果与执行声明和初始化,然后使用临时变量作为转换的结果相同。[...]static_cast<T>(e)
T t(e);
t
对于逆static_cast<>
(从void*
到T*
),第 5.2.9/13 节规定:
“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 T 是对象类型,而 cv2 与 cv1 具有相同的 cv 限定或大于 cv1 的 cv 限定。[...] 类型指针的值转换为“指向 cv void 的指针”并返回,可能具有不同的 cv 限定,应具有其原始值。
因此,如果您有一个void*
指向T
对象存储的指针(这是从 aT*
到对象的隐式转换产生的指针值,那么 astatic_cast
到 aT*
将产生一个指向该对象的有效指针。
回到你的问题,前面的几点暗示如果你有
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
正好覆盖 的存储的第一个 size(T) 字节t_
,因此pvT == pvt_
pvt_ == static_cast<void*>(&t_)
static_cast<T*>(pvT) == pT
- 合起来产生
static_cast<T*>(static_cast<void*>(&t_)) == pT