首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从std::aligned_union_t获取指向包含的对象的指针

从std::aligned_union_t获取指向包含的对象的指针
EN

Stack Overflow用户
提问于 2017-12-30 01:23:57
回答 2查看 177关注 0票数 4

我想使用placement-new在std::aligned_union_t中构造一个任意类型的对象。一旦构造成功,我希望能够取回指向构造的对象的指针,而无需单独存储它。只要我确保将其强制转换为构造的原始类型,通过简单地对std::aligned_union_t执行reinterpret_cast操作是否合法?

下面的代码演示了上面的内容,是合法的吗?要做到这一点,MyStruct应该满足什么类型特征要求呢?例如,它必须是POD吗?

代码语言:javascript
复制
#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;
}
EN

回答 2

Stack Overflow用户

发布于 2017-12-30 01:36:49

这里的reinterpret_cast应该是安全的。最新的标准草案说:

[expr.reinterpret.cast]

对象指针可以显式转换为不同类型的对象指针。当对象指针类型的prvalue _ v被转换为对象指针类型“指向cv _T的指针”时,结果是static_­cast<cv T*>(static_­cast<cv void*>(v))。注意:将“指向T1的指针”类型的Pr值转换为“指向T2的指针”类型(其中T1T2是对象类型,其中T2的对齐要求并不比T1的对齐要求更严格),然后将其转换回其原始类型将生成原始的指针值。- end笔记 

相关问题:

票数 1
EN

Stack Overflow用户

发布于 2017-12-30 02:37:39

不幸的是,这是标准所禁止的。在C++标准reinterpret_cast中,从一个指向对象a的指针到另一个不同类型的对象b的指针被声明为只有当两个对象是可相互转换的指针时才有效,[basic.compound]/4

两个对象a和b在以下条件下是指针可相互转换的:

  • 它们是同一个object,或

  • 一个是联合对象,另一个是该对象(class.union)或

的非静态数据成员

  • 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有非静态数据成员,则是该对象的第一个基类子对象(class.mem)或

存在一个对象c,使得a和c是指针可相互转换的,而c和b是pointer-interconvertible.的(

如果两个对象是指针可相互转换的,那么它们具有相同的地址,并且可以通过reinterpret_­cast从指向另一个对象的指针获取指向另一个对象的指针。 注意:数组对象和它的第一个元素不是指针可相互转换的,即使它们具有相同的地址。- end笔记 

指针具有正确的类型和正确的值(内存地址)并不能使其成为有效的指针。这种令人惊讶的行为的典型例子是:

代码语言:javascript
复制
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):

代码语言:javascript
复制
reinterpret_cast<MyStruct*>(reinterpret_cast<std::uintptr_t>(addressof(g_storage));
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48026143

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档