2

私は非常に小さなObservable実装を書きました。オブザーバーが登録されると、古いオブザーバーが削除され、新しいオブザーバーが作成されます。ただし、初期化されていない場合でも、ポインターを削除しようとします。コードは次のとおりです。

Observable.h

class Observable
{
public:
    Observable();
    virtual void registerObserver(Observer * O);
    virtual ~Observable();

protected:
    Observer * myObserver;
};

Observable.cpp

#include "Observable.h"

Observable::Observable()
{
}


Observable::~Observable()
{
    if(myObserver)
        delete myObserver;
}

void Observable::registerObserver(Observer * O)
{
    if(myObserver)
        delete myObserver;
    myObserver=O;
}

すべての主な機能は

GUI * gui = new GUI();      // GUI extends Observer
Model * m = new Model();    //Model extends Observable
m->registerObserver(gui);   //I get a segfault inside this call

をステップ実行するregisterObserverと、 を初期化していなくてもmyObserver、ステートメントif(myObserver)がtrueと評価されることがわかります。これにより、初期化されていないポインターが削除され、セグ フォールトが発生します。

リリース ビルドを実行すると、segfault が発生しないことに注意してください。デバッグビルドでのみエラーが発生します。

if(myObserver)は、ポインターが無傷の場合にのみtrueと評価されるという印象を受けました。(つまり、初期化され、削除されていません)。

4

5 に答える 5

6

他の人は、初期化されていないポインターが原因でセグメンテーション違反が発生する理由と、それを修正する方法を説明しています。3 つのルールに従っていないため、まだ他のバグが発生するのを待っています。Observableクラスのコピーを作成すると、両方のインスタンスに のコピーが含まれるようになり、両方がそれぞれのデストラクタでポインタmyObserverを試行するため、未定義の動作が発生し、クラッシュする可能性があります。delete

より良い実装は、ゼロの規則に従い、ポインターを自分で管理しないことです。

#include <memory>

class Observable
{
public:
    Observable();
    virtual void registerObserver( std::unique_ptr<Observer> O );
    virtual ~Observable();

protected:
    std::unique_ptr<Observer> myObserver;
};

Observable::Observable()
// no need to initialize pointer
{}

Observable::~Observable()
{
  // no need to delete pointer manually
}

void Observable::registerObserver( std::unique_ptr<Observer> O )
{
    myObserver.reset( O.release() );
}
于 2013-06-06T02:10:45.487 に答える
1

それは正しい。初期化していないため、値はundefinedです。つまり、値が設定されていないため、含まれている可能性のある値がわからないということです。NULL であることが保証されているわけではありません。

常にポインタを初期化する必要があります。通常の方法は、コンストラクターで初期化リストの構文を使用してこれを行うことです。

Observable::Observable()
    : myObserver(NULL)
{ }
于 2013-06-06T02:01:52.917 に答える