0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[C++]動的配列のコピー

Last updated at Posted at 2025-04-08

経緯
動的配列を扱うArrayクラスを作成中。=を演算子オーバーロードすることで、メンバ配列m_arrayに別オブジェクトのm_arrayをコピーできるようにしたい。(蛇足ですが、動的配列を扱う標準のクラステンプレートとしてvectorがあるので、動的配列を使いたい場合はそれを使えば良いと思います。)

質問:「このコードに問題はありますか?
例えば、newに失敗した場合の処理はしなくてよいのでしょうか?」

template <typename TYPE>
  Array<TYPE>::operator=(const Array& other)
{
    TYPE* array = new TYPE[other.m_size];
    delete[] m_array;
    m_array = array;
    m_size = other.m_size;
    std::copy(other.m_array, other.m_array + m_size, m_array);
}

以下はChatGPTの回答。


このコードは基本的に動作すると思われますが、いくつかの重要な点を考慮すると、改善が可能です。特に「new に失敗した場合」については、エラーハンドリングを追加するのが望ましいです。

問題点と改善点

  1. new の失敗時の処理
    new 演算子が失敗した場合、std::bad_alloc 例外が投げられます。C++ では、new が失敗すると、メモリ確保に失敗したことを示す std::bad_alloc という例外がスローされます。しかし、new 演算子が失敗したときにメモリリークを防ぐために、例外処理を適切に行うことが重要です。

    現在のコードでは、new でメモリを確保した後、delete[] を使って古いメモリを解放していますが、new が失敗した場合に例外が発生するため、delete[] の行が実行されることはありません。

    しかし、new 演算子の失敗時に例外をキャッチして、メモリリークを防ぐ方法もあります。次のように、例外処理を使ってより安全にメモリ管理を行うことができます。

  2. メモリリークを防ぐための改善案
    もし new によってメモリ確保に失敗した場合、以前確保したメモリ(m_array)が解放されない可能性があります。これを防ぐために、new を使ってメモリを確保する前に、現在のメモリを保存しておいて、失敗した場合に古いメモリを解放するという方法を取るのが良いです。

    また、std::copy は確保されたメモリに値をコピーしますが、もしメモリ確保に失敗した場合は、最初にメモリを解放しないと、メモリリークの原因になることもあります。

  3. 例外処理を使った改善
    C++では、メモリ確保時に失敗した場合に例外が発生しますが、std::nothrowtry-catch を使ってエラーハンドリングを行うことができます。

改善案

以下は改善したコード例です:

template <typename TYPE>
Array<TYPE>& Array<TYPE>::operator=(const Array& other) {
    if (this != &other) {  // 自己代入のチェック
        TYPE* array = nullptr;
        try {
            array = new TYPE[other.m_size];  // メモリ確保
        } catch (const std::bad_alloc& e) {
            // メモリ確保に失敗した場合の処理
            std::cerr << "Memory allocation failed: " << e.what() << std::endl;
            throw;  // 例外を再スローして呼び出し元で処理
        }

        delete[] m_array;  // 古いメモリを解放
        m_array = array;
        m_size = other.m_size;
        std::copy(other.m_array, other.m_array + m_size, m_array);
    }
    return *this;
}

主な変更点

  1. try-catch ブロック:
    メモリ確保時 (new) に失敗する可能性があるため、try-catch で例外処理を行っています。std::bad_alloc 例外がスローされた場合に適切にエラーメッセージを表示し、再スローして呼び出し元にエラーを伝えます。

  2. 自己代入のチェック:
    if (this != &other) のチェックを追加して、自己代入(a = a; など)を防いでいます。これを行わないと、メモリを解放した後に元のメモリをコピーしようとして不正な動作をする可能性があります。

  3. エラーハンドリング:
    メモリ確保に失敗した場合にエラーメッセージを表示し、再度例外を投げることで、呼び出し元で処理できるようにしています。

まとめ

  • メモリ確保が失敗した場合の処理を行うことは重要です。C++ では、new 演算子が失敗すると std::bad_alloc がスローされますので、適切な例外処理を追加することが推奨されます。
  • 自己代入のチェックやエラーハンドリングのために、改善されたコードを実装することが、安全で堅牢なコードを書くために重要です。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?