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;
}
}
- 这本书没有展示复制构造函数的实现,但对我来说重要的是;他说:“当我们从复制构造函数调用
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_
尚未在复制构造器中初始化。
现在,如果我取消对复制构造函数对默认构造函数 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
的第一个成员在书中的复制构造函数中默认初始化是什么意思?谢谢!
书错了。由于没有任何变体成员的默认成员初始化器,并且由于没有任何变体成员的成员初始化器,因此没有任何变体成员的初始化。第一个变体成员不活跃(其他成员也不活跃)。
你好,我从 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 theunion
will have been initialized. Because ourstring
is not the first member, we know that theunion
member doesn’t hold astring
. In the assignment operator, it is possible that theunion
already holds astring
. We’ll handle that case directly in the assignment operator. That waycopyUnion
can assume that if its parameter holds astring
,copyUnion
must construct its ownstring
: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_
尚未在复制构造器中初始化。
现在,如果我取消对复制构造函数对默认构造函数 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
的第一个成员在书中的复制构造函数中默认初始化是什么意思?谢谢!
书错了。由于没有任何变体成员的默认成员初始化器,并且由于没有任何变体成员的成员初始化器,因此没有任何变体成员的初始化。第一个变体成员不活跃(其他成员也不活跃)。