繁体   English   中英

联合成员分配时的 C++ 分段错误

[英]C++ Segmentation Fault at Union Member Assignment

以下代码在分配给union成员时产生分段错误。 这一定是工会误解的结果,但我无法确定我的错误。

Q1:是否需要在 T1 的构造函数中为相应的 union 成员变量包含一些初始化?

我尝试了类似于建议的解决方案(在下面的代码块中找到)来初始化适当的成员,但没有成功。

Q2:如果 T1 初始化正常,为什么分配给这个位置会产生分段错误?

相关代码:

struct T1
{
    T1(int type)
    {
        this->type = type;
        //Q1 : need to init appropriate union struct here also? Something like:
        /*
        *if (type == 1)  
        *{
        *    union_member1.str = "";
        *}
        *else
        *{
        *    union_member2.value = 0;
        *}
        */
        //If so, better alternative to this?
    }

    int type;           //tells which union struct is used
    
    union               
    {
        struct              //type 1
        {
            std::string str;
        } union_member1;

        struct              //type 2
        {
            int value;
        } union_member2;
    };
};

struct T2
{
    bool used;
    /*
    * other variables here
    */
}; 

std::map<std::string, T2> mymap;
T1* global_ptr;

int main()
{
    for (auto& map_entry : mymap)
    {
        if (!(map_entry.second.used))
        {
            global_ptr = new T1(1);                                 
            global_ptr->union_member1.str = map_entry.first;        //Q2: SEG fault occurs with this assignment
            std::string s = map_entry.first;                        //    but not with this assignment
        }
    }
}

GDB Output

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b70b03 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6

显然,出于可读性的原因,这段代码被删减了。 Map 条目也已经过彻底验证。

https://eel.is/c++draft/class.union#general-6

表示您可以通过ux =...更改联合的活动成员,前提是该赋值是一个普通的赋值运算符。 std::string赋值运算符不是微不足道的,因此注释适用

https://eel.is/c++draft/class.union#general-7

在上述规则不适用的情况下,联合的活动成员只能通过使用放置新表达式来更改。

如果字符串直接是工会成员,你会做

    if (type == 1)  
    {
        new (&union_member_str) std::string();
    }

但它是联合成员的子对象,它是一个未命名的struct类型,因此您改为使用placement new 来构造整个struct并处理其所有子对象:

    if (type == 1)  
    {
        using UMT = decltype(union_member1);
        // or
        // typedef decltype(union_member1) UMT;
        new (&union_member1) UMT();
    }

当然,您还需要正确处理复制构造函数、移动构造函数、复制赋值、移动赋值和析构函数(5 规则)。 使用现有的 class (例如std::variant )要好得多。

直接字符串成员的相应析构函数片段是

    if (type == 1)  
    {
        union_member_str.string::~string();
    }

并为您未命名的struct类型

    if (type == 1)  
    {
        using UMT = decltype(union_member1);
        union_member1.UMT::~UMT();
    }

甚至不要尝试在没有 typedef / type 别名的情况下编写这些。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM