联合成员分配时的 C++ 分段错误
C++ Segmentation Fault at Union Member Assignment
以下代码在分配给 union
成员时产生分段错误。这一定是误解了工会的结果,但我无法查明我的错误。
Q1: 是否有必要在 T1 的构造函数中为适当的联合成员变量包含一些初始化?
我尝试了类似于建议的解决方案(在下面的代码块中找到)来初始化适当的成员,但没有成功。
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 输出
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
显然,出于可读性原因,此代码已被削减。地图条目也已经过彻底验证。
https://eel.is/c++draft/class.union#general-6
说你可以通过 u.x = ...
改变一个联合的活跃成员,只有当那个赋值是一个平凡的赋值运算符时。 std::string
赋值运算符并不简单,因此注释适用
https://eel.is/c++draft/class.union#general-7
In cases where the above rule does not apply, the active member of a union can only be changed by the use of a placement new-expression.
如果字符串直接是联合成员,你会这样做
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 / 类型别名的情况下编写这些内容。
以下代码在分配给 union
成员时产生分段错误。这一定是误解了工会的结果,但我无法查明我的错误。
Q1: 是否有必要在 T1 的构造函数中为适当的联合成员变量包含一些初始化?
我尝试了类似于建议的解决方案(在下面的代码块中找到)来初始化适当的成员,但没有成功。
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 输出
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
显然,出于可读性原因,此代码已被削减。地图条目也已经过彻底验证。
https://eel.is/c++draft/class.union#general-6
说你可以通过 u.x = ...
改变一个联合的活跃成员,只有当那个赋值是一个平凡的赋值运算符时。 std::string
赋值运算符并不简单,因此注释适用
https://eel.is/c++draft/class.union#general-7
In cases where the above rule does not apply, the active member of a union can only be changed by the use of a placement new-expression.
如果字符串直接是联合成员,你会这样做
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 / 类型别名的情况下编写这些内容。