我想在Union里面使用字符串.如果我写如下
union U
{
int i;
float f;
string s;
};
Run Code Online (Sandbox Code Playgroud)
编译器给出错误,说U :: S有复制构造函数.
我读了一些其他帖子,了解解决这个问题的其他方法.但我想知道为什么编译器首先不允许这样做?
编辑:@KennyTM:在任何联合中,如果成员被初始化,其他人将具有垃圾值,如果没有初始化,则所有将具有垃圾值.我认为,标记联合只是为从Union访问有效值提供了一些安慰.您的问题:您或编译器如何在没有额外信息的情况下为联合编写复制构造函数?sizeof(string)给出4个字节.基于此,编译器可以比较其他成员大小并分配最大分配(在我们的示例中为4字节).内部字符串长度无关紧要,因为它将存储在单独的位置.让字符串为任意长度.Union必须知道的是使用字符串参数调用字符串类复制构造函数.无论哪种方式编译器发现在正常情况下都必须调用复制构造函数,即使字符串在Union中,也要遵循类似的方法.所以我认为编译器可以这样做,分配4个字节.然后,如果为s分配了任何字符串,则字符串类将使用其自己的分配器来处理该字符串的分配和复制.所以也没有内存损坏的可能性.
编译器中Union开发时不存在字符串吗?所以我的答案还不清楚.我是这个网站的新工作人员,如果有什么不对,请原谅.
ken*_*ytm 58
因为在联合中具有一个具有非平凡(复制/)构造函数的类没有意义.假设我们有
union U {
string x;
vector<int> y;
};
U u; // <--
Run Code Online (Sandbox Code Playgroud)
如果U是一个结构,u.x
并且u.y
将分别初始化为空字符串和空向量.但是工会成员共享同一个地址.因此,如果u.x
初始化,u.y
将包含无效数据,反之亦然.如果它们都未初始化,则无法使用它们.在任何情况下,在联合中使用这些数据都不容易处理,因此C++ 98选择否认:(§9.5/ 1):
具有非平凡构造函数(12.1),非平凡复制构造函数(12.8),非平凡析构函数(12.4)或非平凡复制赋值运算符(13.5.3,12.8)的类的对象不能是一个联盟的成员,也不是一系列这样的对象.
在C++ 0x中,此规则已经放宽(§9.5/ 2):
联合的至多一个非静态数据成员可以具有支撑或等于初始化器.[ 注意:如果union的任何非静态数据成员具有非平凡的默认构造函数(12.1),复制构造函数(12.8),移动构造函数(12.8),复制赋值运算符(12.8),移动赋值运算符(12.8),或者析构函数(12.4),联合的相应成员函数必须是用户提供的,否则将为联合隐式删除(8.4.3).- 结束说明 ]
但是仍然无法为联合创建(正确)con /析构函数,例如,如果没有额外信息,您或编译器如何为上面的联合编写复制构造函数?要确保联合的哪个成员处于活动状态,您需要一个标记的联合,并且需要手动处理构造和破坏,例如
struct TU {
int type;
union {
int i;
float f;
std::string s;
} u;
TU(const TU& tu) : type(tu.type) {
switch (tu.type) {
case TU_STRING: new(&u.s)(tu.u.s); break;
case TU_INT: u.i = tu.u.i; break;
case TU_FLOAT: u.f = tu.u.f; break;
}
}
~TU() {
if (tu.type == TU_STRING)
u.s.~string();
}
...
};
Run Code Online (Sandbox Code Playgroud)
但是,正如@DeadMG所提到的,这已经实现为或.boost::variant
boost::any
Pup*_*ppy 26
想一想.编译器如何知道联合中的类型?
它没有.联盟的基本操作基本上是一个按位演员.联合中包含的值的操作只有在每种类型基本上都可以填充垃圾时才是安全的.std::string
不能,因为这会导致内存损坏.使用boost::variant
或boost::any
.
Kea*_*eks 14
在C++ 98/03中,union的成员不能具有构造函数,析构函数,虚拟成员函数或基类.
基本上,您只能使用内置数据类型或POD
请注意,它在C++ 0x中发生了变化:Unrestricted union
union {
int z;
double w;
string s; // Illegal in C++98, legal in C++0x.
};
Run Code Online (Sandbox Code Playgroud)
从C++规范§9.5.1开始:
具有非平凡构造函数,非平凡复制构造函数,非平凡析构函数或非平凡复制赋值运算符的类的对象不能是并集的成员.
这个规则的原因是编译器永远不会知道哪个析构函数/构造函数调用,因为它从来不知道哪个可能的对象在union中.