C++ Primer 第 5 版联合和 class 类型的成员

C++ Primer 5th edition unions and members of class type

你好,我从 C++ 入门第 5 版 ch 19.6 联合中得到了这个:

class Token {
public:
    // copy control needed because our class has a union with a string member
    // defining the move constructor and move-assignment operator is left as an exercise
   Token(): tok(INT), ival{0} { }
   Token(const Token &t): tok(t.tok) { 
       copyUnion(t); 
   }
   Token &operator=(const Token&);
   // if the union holds a string, we must destroy it; see § 19.1.2 (p. 824)
   ~Token() { if (tok == STR) 
       sval.~string(); }
   // assignment operators to set the differing members of the union
   Token &operator=(const std::string&);
   Token &operator=(char);
   Token &operator=(int);
   Token &operator=(double);
private:
   enum {INT, CHAR, DBL, STR} tok; // discriminant
   union { // anonymous union
      char   cval;
      int    ival;
      double dval;
      std::string sval;
   }; // each Token object has an unnamed member of this unnamed union type
   // check the discriminant and copy the union member as appropriate
    void copyUnion(const Token&);
 };

When we call copyUnion from the copy constructor, the union member will have been default-initialized, meaning that the first member of the union will have been initialized. Because our string is not the first member, we know that the union member doesn’t hold a string. In the assignment operator, it is possible that the union already holds a string. We’ll handle that case directly in the assignment operator. That way copyUnion can assume that if its parameter holds a string, copyUnion must construct its own string:

void Token::copyUnion(const Token &t)
{
     switch (t.tok) {
     case Token::INT: ival = t.ival; break;
     case Token::CHAR: cval = t.cval; break;
     case Token::DBL: dval = t.dval; break;
     // to copy a string, construct it using placement new; see         
     case Token::STR: new(&sval) string(t.sval); break;
    }
}

这是我的例子:

struct A{
    A(){std::cout << "A()\n";}
    A(A const&){std::cout << "A(A const&)\n";}
    ~A(){std::cout << "~A()\n";}
};


struct Foo{
    Foo();
    Foo(Foo const&);
    ~Foo();

    enum {CLS_A, INT, CHAR} disc_; // discriminant 
    union {
        A a_; // first member is of class type that's defined its own def-ctor
        int age_;
        char degree_;
    };
};

Foo::Foo() :
    disc_(CLS_A), 
    a_(){ // explicitly initializing the member a_ otherwise it is not initialized

    std::cout << "Foo()\n";
}

Foo::Foo(Foo const&) : /*Foo()*/ { // a_ is not default-init so only if I un-comment the call the def-tor
    std::cout << "Foo(Foo const&)\n";
}

Foo::~Foo(){
    std::cout << "~Foo()\n";
    if(disc_ == CLS_A)
        a_.~A(); // not automatically called
}

int main(){

    Foo f;
    Foo f2 = f;
    
}    

输出:

A()
Foo()
Foo(Foo const&)
~Foo()
~Foo()
~A()

现在,如果我取消对复制构造函数对默认构造函数 A() 的调用的注释:

    Foo::Foo(Foo const&) : Foo(){/*..*/}

输出:

A()
Foo()
A()
Foo()
Foo(Foo const&)
~Foo()
~A()
~Foo()
~A()

这是他的拷贝构造函数:

 Token(const Token &t): tok(t.tok) { // didn't initialize any member of the `union`
   copyUnion(t); 
}

现在可以了。那么union的第一个成员在书中的复制构造函数中默认初始化是什么意思?谢谢!

书错了。由于没有任何变体成员的默认成员初始化器,并且由于没有任何变体成员的成员初始化器,因此没有任何变体成员的初始化。第一个变体成员不活跃(其他成员也不活跃)。