字符串在union,segfault中

时间:2016-11-03 07:19:59

标签: c++ segmentation-fault c++14 unions

这基本上是一个标记的联合:

#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*吗?如果是这样,为什么?

1 个答案:

答案 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);
}