今天同事遇到一个关于拷贝构造函数的问题。代码大致如下:
class test { public: test( size_t size ) { v.assign( size, 1 ); } test( const test& rhs) { v = rhs.v; } ~test(){} private: vector<int> v; }; class another { public: another() :v(7) { } another( const another& rhs ) { v = rhs.v; } ~another(){} private: test v; };
咋一看,貌似没有问题,但是gcc却编译不过去。报错如下:
在上面代码中,test类明明已经有构造函数和拷贝构造函数,为什么gcc一定要我给出一个默认构造函数出来呢?这个问题,就牵涉到了C++构造函数中的初始化列表问题了。
在编写构造函数的时候,很多人都会意思到使用初始化列表来达到避免多次构造的资源损耗,但是,在编写拷贝构造函数的时候,我们大部分时间都是这样写的。
class test { public: test():a(0){.....} test( const test& rs ){ a = rs.a; ...} ~test(){} private: int a; };
而这就是造成这个问题的症结所在了。对于类而言,成员变量仅仅是声明一个变量,而真正的定义是在构造函数中做的,所以,如果在构造函数(包括拷贝构造函数)中,如果成员变量不是在初始化列表中进行初始化的话,像上面代码中的拷贝构造函数的写法,其实过程就相当于先调用一次默认构造函数对成员变量进行初始化,然后再调用=操作对成员变量进行赋值。因此,这就出现了上述gcc要求提供默认构造函数的问题了。
为了解决这个问题,我们借助初始化列表这个很好的东东,把代码改成如下,问题就不见了。
class test { public: test( size_t size ) { v.assign( size, 1 ); } test( const test& rhs) :v( rhs.v) { } ~test(){} private: vector<int> v; }; class another { public: another() :v(7) { } another( const another& rhs ) :v(rhs.v) { } ~another(){} private: test v; };