从 std::aligned_union_t 获取指向包含对象的指针
Getting pointer to contained object from std::aligned_union_t
我想在std::aligned_union_t
内使用放置-new构造一个任意类型的对象。成功构造后,我希望能够取回指向构造对象的指针,而无需单独存储它。只要我确保将其转换为构造的原始类型,只需简单地reinterpret_cast
'ingstd::aligned_union_t
就可以这样做是否合法?
以下举例说明上述内容的代码是否合法?是否有任何MyStruct
应该满足的类型特征要求?例如,它必须是 POD 吗?
#include <type_traits>
#include <memory>
#include <cstddef>
#include <exception>
struct MyStruct
{
int value = 0;
};
constexpr size_t c_alignedUnionSize = 10;
std::aligned_union_t<c_alignedUnionSize, std::max_align_t> g_storage;
MyStruct* GetPtr()
{
return reinterpret_cast<MyStruct*>(std::addressof(g_storage));
}
void Construct()
{
if (sizeof(MyStruct) > sizeof(g_storage))
{
std::terminate();
}
auto ptr = new (std::addressof(g_storage)) MyStruct{};
if (!ptr)
{
std::terminate();
}
GetPtr()->value = 123;
}
void Destroy()
{
GetPtr()->~MyStruct();
}
int GetValue()
{
return GetPtr()->value;
}
int main()
{
Construct();
auto value = GetValue();
Destroy();
return value;
}
这里的reinterpret_cast
应该是安全的。最新的标准草案说:
[重新诠释]
对象指针可以显式转换为不同类型的对象指针。当对象指针类型的 prvalue
v
转换为对象指针类型"指向 cvT
的指针"时,结果为static_cast<cv T*>(static_cast<cv void*>(v))
。[ 注意:将类型为"指向T1
的指针"的 prvalue 转换为"指向T2
的指针"类型(其中T1
和T2
是对象类型,其中T2
的对齐要求不比T1
的对齐要求更严格)并返回其原始类型将生成原始指针值。— 尾注 ]
相关问题:
- aligned_storage和严格的混叠
不幸的是,这是标准所禁止的。在C++标准reinterpret_cast
中,从一个指针到对象a到另一个不同类型的对象b被声明为仅在两个对象指针可相互转换时才有效,[basic.compound]/4:
在以下情况下,两个对象 a 和 b 是指针可相互转换的:
它们是同一对象,或者
- 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,
一个是联合对象,另一个是该对象的非静态数据成员([class.union]),或者
或者,如果该对象没有非静态数据成员,则为该对象的第一个基类子对象 ([class.mem]),或者
存在一个对象 C,使得 A 和 C 是指针可相互转换的,C 和 B 是指针可相互转换的。
如果两个对象是指针可相互转换的,则它们具有相同的地址,并且可以通过
reinterpret_cast
从指向另一个对象的指针获取指向一个对象的指针。[注意:数组对象及其第一个元素不是指针可相互转换的,即使它们具有相同的地址。
指针具有正确的类型和正确的值(内存地址)这一事实并不能使其成为有效的指针。这种令人惊讶的行为的典型例子是这样的:
alignas(int) unsigned char buff[2*sizeof(int)];
auto p1 = new(buff) int{};
auto p2 = new(buff+sizeof(int)) int{};
*(p1+1) = 10;//Undefined behavior
//p1+1 does not point to *p2 even if p1 and p2 have same type and value.
因此,要符合标准,必须存储new
返回的指针的值。
我找到了一个很好的解决方案,包括将指针强制转换为整数类型,以及将指针强制转换为其他指针类型,这将导致实现定义的行为([expr.reinterpret_cast]/5):
reinterpret_cast<MyStruct*>(reinterpret_cast<std::uintptr_t>(addressof(g_storage));
- 是否需要删除包含对象的"pair"?
- 如何在h文件中包含.o对象文件
- 指针数据类型变量如何包含对象?
- C++ 矢量不显示包含对象的数据
- 唯一 ptr 将所有权移动到包含对象的方法
- 通过引用返回包含对象的向量
- 仅在删除包含对象的向量时调用自定义»析构函数«
- QML中包含对象的QABSTRACTLISTMODEL的缺点
- std::list::merge() 对于包含对象的列表失败
- 从 std::aligned_union_t 获取指向包含对象的指针
- 通过QLIST迭代并在包含对象上调用函数
- 检查子对象的地址是否在包含对象的边界内是否合法
- std::vector 调用在重新分配时无论如何都包含对象的析构函数?
- C++ 如何获取对包含对象的引用
- 从包含对象指针的列表中删除
- 对于数据成员,如果包含对象已在动态内存中,则动态分配此变量(或不动态分配)之间是否有任何区别
- C++标准库容器相对于所包含对象的线程安全性
- 包含对象的结构的向量
- 包含对象的 C++ 结构
- 正在计算包含对象的此指针