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

Posted

技术标签:

【中文标题】C++ Primer 第 5 版联合和类类型成员【英文标题】:C++ Primer 5th edition unions and members of class type 【发布时间】:2021-08-23 22:42:27 【问题描述】:

您好,我从 C++ 入门第 5 版 ch 19.6 unions 得到这个:

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), ival0  
   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&);
 ;

当我们从复制构造函数调用copyUnion 时,联合成员将被默认初始化,这意味着union 的第一个成员将被初始化。因为我们的string 不是第一个成员,所以我们知道union 成员没有string。在赋值运算符中,union 可能已经拥有string。我们将直接在赋值运算符中处理这种情况。这样copyUnion可以假设如果它的参数持有一个stringcopyUnion必须构造它自己的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;
    

这本书没有展示复制构造函数的实现,但重要的是我;他说:“当我们从复制构造函数调用copyUnion 时,联合成员将被默认初始化,这意味着union 的第一个成员将被初始化......”但我认为没有成员作为class 一部分的union 对象是默认初始化的,因此它必须在copy-ctor-init-list 中显式初始化。

这是我的例子:

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 的 dtor 只调用了一次,因为 f2 对象的成员 a_ 尚未在 copy-ctor 中初始化。

现在,如果我取消注释从 copy-ctor 对 default-ctor 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 的第一个成员在书中的复制构造函数中默认初始化是什么意思?谢谢!

【问题讨论】:

您需要展示更多关于这本书的背景信息,我们才能回答。课堂是什么样子的?工会呢?您的示例与书中的代码完全匹配吗? @eerorika:我已经编辑过了。 【参考方案1】:

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

【讨论】:

好的,非常感谢。我真的很难理解它。 为了简洁起见,我刚刚将我的 copy-ctor 中的初始化委托给了 default-ctor。

以上是关于C++ Primer 第 5 版联合和类类型成员的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer Plus学习:第十章

《C++Primer(第5版)》第九章笔记

抽奖98新《C++ Primer 英文版(第5版)》

好书推荐|C++ Primer中文版(第5版)(附PDF下载)

好书推荐|C++ Primer中文版(第5版)(附PDF下载)

C++ Primer 5th笔记(chap 19 特殊工具与技术)union