写了一个String的类,没有拷贝构造函数,但是有拷贝赋值操作符。
代码:
#include <iostream> #include <cstring> using namespace std; class String { public: String():data(0){ cout << "String()" << endl; } String(const char *str):data(0) { int len = strlen(str); data = new char[len + 1]; strcpy(data, str); cout << "String(char*)" << endl; } /× String(const String &str):data(0) { if (this != &str) { delete [] data; data = new char[strlen(str.data) + 1]; strcpy(data, str.data); } cout << "String(String&)" << endl; } ×/ ~String() { cout << "~String()" << data << endl; delete [] data; } String& operator=(const String &str) { if (this != &str) { delete [] data; data = new char[strlen(str.data) + 1]; strcpy(data, str.data); } cout << "=(String&)" << endl; return *this; } String& operator=(const char *ch) { if (ch) { delete [] data; data = new char[strlen(ch) + 1]; strcpy(data, ch); } cout << "=String(char*)" << endl; return *this; } void show() { if (data) cout << data << endl; else cout << "data is null" << endl; } private: char *data; };
int main(void) { String s; s = "hello world!"; s.show(); String ss = s; ss.show(); return 0; }
运行会出现:
String() =String(char*) hello world! hello world! ==(String&, String&) ss is equal s ~String()hello world! ~String()
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x08ee2008 *** ======= Backtrace: ========= /lib/tls/i686/cmov/libc.so.6(+0x6b591)[0x17b591]。。。。。。。。
这样的错误。
开始一头雾水,怎么也不应该出现这样的问题。后来发现原因在于:
String ss = s;
开始我以为这行代码会调用拷贝赋值操作符的函数,但是他却没有调用。因为这行代码是初始化ss,而不是赋值。他会去调用拷贝构造函数。加上拷贝构造函数问题就可以解决了。或者不加但是这样
//String ss = s; String ss; ss = s;
也可以。
初始化与赋值的问题在这样的情况下也有区别:
class Clazz { public: Clazz(const stirng &str):data(str){} // 初始化 // Clazz(const string &str){data = str;} // 赋值 private: string data; };
在初始化列表中,data会被直接初始化为str,即直接调用string的拷贝构造函数。
在赋值的情况下,
Clazz(const string &str){data = str;}
会被转换成类似这样的形式:
Clazz(const string &str):data(){data = str;}
即data的初始化分成两步,先调用string的默认构造函数,然后在调用一次拷贝赋值操作符。
所以如果可以,尽量将成员的初始化放在初始化列表中是一个不错的选择。
在《c++ primer》中是这样说的,一般情况下,初始化比赋值的效率要高。