1

私は次の記事を指摘されました:

http://www.codeproject.com/Tips/78946/C-Copy-Constructor-in-depth

コードは次のとおりです。

class string
{
    // constructor
    string(char* aStr)
    {
        str = new char[sizeof(aStr)];
        strcpy (str,aStr);
    }

    // destructor
    ~string() 
    {
        del str;
    }

    char *getChars(){ return str; }
    char* str;
};


void function (string str)
{
    // do something 
}


void main ()
{
    string str("hello");
    function(str);
    function(str); // program crashes
}

mainで、2回目の呼び出しで問題が発生する理由がわかりませんfunction。確かにstr、が最初の呼び出しに渡されるとき、これはのコピーにすぎないため、内部でstr行われたことは、 ?で宣言された変数に影響を与えません。strfunctionstrmain

4

4 に答える 4

3

デフォルトのコピーコンストラクタは、オブジェクトのビットごとのコピーを実行します。つまり、ポインタメンバーはコピーされますが、それが指すオブジェクトはコピーされません。デフォルトのコンストラクターを使用し、浅いコピーのみを実行する場合、両方のオブジェクトのポインターは同じオブジェクトを指します。

あなたの質問に固有:

初めてfunction(str)すべてを正常に呼び出すと、関数が終了すると、スタックの入力引数が破棄され(これはのコピーですstrが、デフォルトのコピーコンストラクターを使用すると、ポインターは元のオブジェクトと同じ場所を指します)、デストラクタは、ポインタが指すオブジェクトを削除するために呼び出されます。

2回目に、を呼び出しfunction(str)、関数が終了すると、デストラクタは、のポインタが指すアドレスを解放しようとしstr、クラッシュします。

このような問題を回避するには、独自のコピーコンストラクターを定義する必要があります。このコンストラクターは、ポインターだけでなくオブジェクトも適切にコピーし、ディープコピーを実行します。

于 2013-03-11T21:56:01.153 に答える
2

問題はstr、クラスのメンバーがstringポインターであるということです。つまり、文字列のコピーが作成されると、このポインタの値がコピーされますが、ポインタの値は単なるメモリの場所です。したがって、を呼び出すとfunction(str)、ポインタの値は変更されていなくても、その場所のメモリが変更されます。

于 2013-03-11T21:56:09.347 に答える
1

デフォルトでは、C ++は、デフォルトのコピーコンストラクターを使用してデータのシャローコピーを実行する方法しか知りません。したがって、はい、最初の呼び出しfunctionはの「コピー」を作成しますが、コピーされたのは文字列クラスstrのインスタンスデータであったため、このコピーはあまりコピーではありません。char*つまり、C ++はアドレスをコピーしているだけですが、実際に新しい文字列にスペースを割り当てて内容をコピーするほど賢くはありません。カスタムコピーコンストラクタを使用して、自分でそれを行う必要があります。

于 2013-03-11T21:59:06.413 に答える
0

のコンストラクタはstr、後続のへの呼び出しに十分なバイトを割り当てませんstrcpy。その後、すべての賭けはオフになります。それが修正されたら、適切なコピーコンストラクターとコピー代入演算子を記述します。

于 2013-03-12T04:11:37.977 に答える