c++コピーコンストラクタとコピー付与オペレータの問題
3587 ワード
Stringクラスが書かれています.コンストラクタはコピーされていませんが、コピー付与オペレータがあります.
コード:
次のように実行されます.
こんな間違い.
最初は霧の水で、どうしてもこのような問題が発生するべきではありません.その後、原因は次のとおりです.
最初は、この行のコードがコピー付与オペレータの関数を呼び出すと思っていましたが、呼び出されませんでした.この行のコードは、付与ではなくssを初期化するためです.彼はコピーコンストラクション関数を呼び出します.コピーコンストラクタの問題を加えると解決できます.あるいは入れないでこのようにします
いいですよ.
初期化と付与の問題は、このような場合でも異なります.
初期化リストでは、dataはstrに直接初期化され、stringのコピーコンストラクタが直接呼び出されます.
付与の場合、
このような形式に変換されます.
すなわちdataの初期化は2つのステップに分けられ、stringのデフォルト構造関数を呼び出し、コピー付与オペレータを1回呼び出す.
したがって、できるだけメンバーの初期化を初期化リストに入れるのは良い選択です.
『c++primer』では、一般的に初期化は付与よりも効率的である.
コード:
#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の初期化は2つのステップに分けられ、stringのデフォルト構造関数を呼び出し、コピー付与オペレータを1回呼び出す.
したがって、できるだけメンバーの初期化を初期化リストに入れるのは良い選択です.
『c++primer』では、一般的に初期化は付与よりも効率的である.