c++コピーコンストラクタとコピー付与オペレータの問題

3587 ワード

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の初期化は2つのステップに分けられ、stringのデフォルト構造関数を呼び出し、コピー付与オペレータを1回呼び出す.
したがって、できるだけメンバーの初期化を初期化リストに入れるのは良い選択です.
『c++primer』では、一般的に初期化は付与よりも効率的である.