美文网首页
union使用

union使用

作者: zlcook | 来源:发表于2020-09-29 18:02 被阅读0次
  • c++11之前,union不能包含定义了析构函数或拷贝控制成员的类类型成员,之后取消了。
  • 如果union提供了初始值,则该值被用于初始化第一个成员。
union Token {
 char cval;
 int ival;
};
Token def ; // 未初始化
Token tk = {'a'} ; // 初始值显示初始化,用于第一个cval成员
 tk.ival = 5;  // 此时cval是未定义状态

包含类类型的union

  • 如果union包含的是内置类型成员,则编译器按照成员次序依次合成默认构造或拷贝控制成员。
  • 如果union含有类类型成员,并且该类型自定义了默认构造函数或拷贝控制成员(移动/拷贝{构造/赋值},析构),则编译器将为union合成对应版本的并将起声明为删除的。(所以,此时用户可以自定义拷贝控制函数,而不使用合成的)
  • 如果一个类含有union成员,而且该union含有删除的拷贝控制成员,则该类与之对应的拷贝控制操作也是删除的。(所以,类也应该自定义拷贝控制成员或默认构造函数)
  • 包含类类型的union,要想构造或销毁类类型成员必须执行非常复杂操作(因为union不知道当前存储的值是哪个类型),因为通常把含有类类型成员的union内嵌在另一个类当中,这个类可以管理并控制与union的类类型成员有关的状态转换。
templace<class T>
class StatusOr {
public:
StatusOr() : state_(kVoid) {}

StatusOr(const StatusOr& rhs) : state_(rhs.state_) {
       if (state_ == kValue) {
            new (&variant_) Variant(rhs.variant_.value_);
        } else if (state_ == kStatus) {
            new (&variant_) Variant(rhs.variant_.status_);
        }
}


StatusOr(Status st) : variant_(st), state_(kStatus) {}

StatusOr(T&&  v) : variant_(v), state_(kValue) {}

~StatusOr() {
  if (state_ == kStatus) {
    variant_.status_.~Status();
  } else (state_ == kValue) {
    variant_.value_.~T();
  }
  state_ = kVoid;
}

private:
// Variant状态判别式
enum State {
   kValue = 0,
   kStatus = 1,
   kVoid = 2,
}; 

union Variant {
  Variant() {}
  Variant(Status status) : status_(status) {}
  Variant(T val) : value_(val) {}
// 如果不自己定义析构,那么Variant的析构默认是删除的,那么StatusOr的析构默认也是删除的
  ~Variant() {}  // 类类型成员的析构交给StatusOr类管理
  Status status_;  // 定义类构造函数和拷贝控制成员的类类型成员
  T      value_;
 }; 

  Variant variant_;  // 未定义
   State state_;
};
  • union包含的是内置类型成员时,我们可以使用普通的赋值语句改变union保存的值。
Token tk = {'a'} ; // 初始值显示初始化,用于第一个cval成员
 tk.ival = 5;  // 此时cval是未定义状态
tk.cval = 'b';   // 普通的赋值语句就可以改变union保存的值。
  • union包含的是类类型成员时,如果想将union的值改为类类型成员对应的值,则必须运行该类型的构造函数;反之,当将union类类型成员的值改为一个其它值(内置或另一个类类型)时,必须运行该类类型的析构函数(如果是未定义没有初值,则不需要析构呀)。
// 拷贝构造,union之前没有值,直接进行构造
StatusOr(const StatusOr& rhs) : state_(rhs.state_) {
       if (state_ == kValue) {
            new (&variant_) Variant(rhs.variant_.value_);
        } else if (state_ == kStatus) {
            new (&variant_) Variant(rhs.variant_.status_);
        }
}

// 拷贝赋值,union之前可能有值,涉及到更改,所以会有析构,再次构造
StatusOr& operator=(const StatusOr& rhs) {
  if (this == &rhs) {
    return *this;
  }
  // 先析构
   if (state_ == kValue) {
        variant_.value_.~T();
   } else if (state_ == kStatus) {
        variant_.status_.~Status();
   }
   // 在构造赋值
   if (rhs.state_ == kValue) {
        new (&variant_) Variant(rhs.value_);
         state_ = kValue;
   } else if (rhs.state_ == kStatus) {
        new (&variant_) Variant(rhs.status_);
         state_ = kStatus;
   }
   return *this;
}
  • union含有一个定义了析构函数的成员变量,则必须为union也定义要给析构函数以销毁成员变量,但是作为union组成部分的类成员无法自动销毁,因为析构函数不清楚union存储的值是什么类型,所以他无法确定应该销魂哪个成员,所以将union作为内部类,由其外部类来销毁union中的类类型成员,如果union中存储的内置类型,则析构函数什么也不做。

相关文章

网友评论

      本文标题:union使用

      本文链接:https://www.haomeiwen.com/subject/bapeuktx.html