0

私は現在 Text と呼ばれる ADT に取り組んでおり、代入演算子をオーバーロードしています。演算子を次のようにテストすると、assignText = alphaすべて正常に出力されます。ただし、実行すると、assignText = assignText代わりに 2 つの実線のバーが出力されます。

assignText は Text オブジェクトとして宣言されています。

私のオーバーロードされた代入演算子は次のとおりです。

void Text::operator= (const Text& other) { 
bufferSize = other.getLength();
buffer = new char[bufferSize];
buffer = other.buffer; 
}

どこint bufferSizeで、char *buffer

ヒントや提案をいただければ幸いです。他に何か必要な場合は、お知らせください。

4

6 に答える 6

1

他の回答では、オペレーターの実装に関するさまざまな問題がすでに指摘されています。ここでは、何が起こっているのか、つまり、観察したとおりにコードが動作する理由を理解しようとします。の場合this == &other、つまり自己割り当て中は、現在の長さを新しいバッファーのサイズとして取得します。その新しいバッファは初期化されていないため、その時点でランダムなバイトが含まれている可能性があります。自己割り当ての場合、最後の割り当てはノーオペレーションです。要約すると:

void Text::operator= (const Text& other) { 
  bufferSize = other.getLength(); // Take length from current object
  buffer = new char[bufferSize];  // Create new buffer, old buffer turns into a memory leak
  buffer = other.buffer;          // No-op as both are the same variable
}

したがって、これが示すことは、現在のオブジェクト サイズのバッファが作成され、コンテンツが未定義になるということです。あなたの場合、未定義のコンテンツはたまたまあなたが言及した垂直バーを表しています。

これを解決するには、他の回答やコメントからの提案に基づいて代入演算子を修正してください。

于 2012-09-08T22:47:08.867 に答える
1

これはメモリ リークです。に 2 つの異なるポインターを割り当てていますbuffer

 buffer = new char[bufferSize];
 buffer = other.buffer; 
于 2012-09-08T21:25:08.923 に答える
1

当面の問題に関しては、C++ の FAQ で説明されています。. 多くの場合、最初に FAQ を読むことをお勧めします。または、少なくともそれをすくい取る。

コピー代入演算子を絶対に実装する必要がある場合は、通常、コピー アンド スワップ イディオムで十分です。また、例外セーフです。次のようになります。

void swapWith( MyType& other ) throw()
{
    // swap them members
}

void operator=( MyType other )
{
    swapWith( other );
}

ここで、コピー コンストラクターは仮引数のコピーを作成し、そこで例外が発生するため、コピー コンストラクターは、コピーが失敗した場合のクリーンアップも一元化します。その後、2 つのオブジェクトの内容が交換され、コピー オブジェクトのデストラクタが、このオブジェクトの内部のものをクリーンアップします。結果のvoid型はまだ慣習的ではありませんが、副作用のある式をサポートするためにコードと時間を浪費するのは賢明ではありません。

これで、バッファに を使用するだけで、これらすべてを回避できます。std::vector

それが私がお勧めする、本当に簡単な解決策です: use std::vector.

于 2012-09-08T21:26:08.627 に答える
0

このコードは完全に機能します

Text& Text::operator=(const Text& other) 
{ 
    if(this == &other) /* checks for self assignment */
         return *this;

    if(NULL == other.buffer)
         return *this;

    if(NULL != buffer) /* assuming buffer=NULL in constructor */
    {
         delete [] buffer;
         buffer = NULL;
    }

    bufferSize = other.getLength();
    buffer = new char[bufferSize+1];
    memset(buffer, 0, bufferSize+1);
    memcpy(buffer, other.buffer, bufferSize);

    return *this;
}

これを試して..

于 2012-09-10T11:28:51.767 に答える
0

いくつかの考えとレビューの後、私はそれを手に入れたと思います。実装を構築する必要があるヘッダー ファイルによって決定される void 関数を記述する必要があるとします。Drew Dormann、MvG、その他のコメントを考慮して、次のように考えました。

void Text::operator= (const Text &other) 
{ 
    if (this != &other) // takes care of self-assignment
    { 
         delete [] buffer; // delete the old buffer
         bufferSize = other.bufferSize; // assign size variable
         buffer = new char[bufferSize + 1]; // create new buffer
         strcpy(buffer, other.buffer); // copy array
    }
}

これは機能し、メモリリークはないと思います。

于 2012-09-10T16:15:11.973 に答える
0

これは、代入演算子が根本的に安全でないためです。最後のステップとして、古い状態を壊す必要があります。検討

Text& Text::operator= (const Text& other) {
    auto new_buffer = new char[other.bufferSize];
    std::copy(other.buffer, other.buffer + other.bufferSize, new_buffer);
    // Now consider whether or not you need to deallocate the old buffer.
    // Then set the new buffer.
    buffer = new_buffer;
    bufferSize = other.bufferSize;
    return *this;
}

これにより、問題が発生した場合でも、オブジェクトが常に有効であることが保証されTextます。また、おまけとして、自己割り当てに対して安全です。適切に作成された代入演算子はすべて、自己代入に対して安全です。

これは、多くの場合、安全性を保証するために、コピーしてからスワップするコピー アンド スワップと結びついています。

于 2012-09-08T21:26:21.193 に答える