这基本上是一个标记的联合:
#include <string>
using std::string;
struct test{
test():tag(INT),i(0){};
test(const test&)=delete;
test& operator=(const test&)=delete;
enum {STRING,INT} tag;
union {
string s;
int i;
};
test& operator=(string s){
this->s=s;
tag=STRING;
return *this;
}
test& operator=(int i){
this->i=i;
tag=INT;
return *this;
}
~test(){
if (tag==STRING)
s.~string();
}
};
int main(){
test instance;
instance="string";
return 0;
}
它会编译,但每次崩溃都会出现Segmentation故障。我只是出于好奇,它是一个非常完整的联合类,提供了一个自定义的析构函数,没有移动,没有副本,那么为什么会崩溃?我必须在工会中使用string*
吗?如果是这样,为什么?
答案 0 :(得分:3)
仔细阅读C ++ 11中的rule of five
这是错误的代码:
/// wrong code test& operator=(string s){ this->s=s; tag=STRING; return *this; }
因为你错误地认为this->s
在分配之前是有效的。你应该使用placement new 构造它(在未初始化的内存区域,从&this->s
开始):
test& operator=(string ss){
if (tag==STRING) { s=ss; return *this; }
new((void*)&s) std::string(ss);
tag=STRING;
return *this;
}
顺便说一句,我想你也应该明确地定义
test(const test&s);
test(const std::string&);
test& operator=(const test&);
test(test&&s);
test& operator=(test&&);
顺便说一句,你显然错过了构造函数:
test(const std::string&str) {
tag = STRING;
new ((void*)(&s)) std::string(str);
}