2

Foo と Bar の 2 つのクラスがあります。Bar は Foo への参照を維持し、Foo のメソッドを呼び出してその状態を変更するメソッドを持っています。コードを以下に示します。

class Foo
{
private:
    double m_value;

public:
    void setValue(double value) { 
        this->m_value = value;
    };

    double getValue() {
        return this->m_value;
    };
};

class Bar
{
private:
    Foo& m_foo;

public:
    Bar() : m_foo(Foo()) {
    };

    void setFooValue(double value) {
        m_foo.setValue(value);
    };

    double getFooValue() {
        return m_foo.getValue();
    };
};    

以下のように、設定後に foo の値にアクセスしようとすると、問題が発生します。

Bar bar;

bar.setFooValue(10000.0);

double value = bar.getFooValue();

std::cout << "Foo value is: " << value << std::endl;

どの出力Foo value is -9.25596e+061. メモリが壊れているようです - なぜですか? m_foo を参照として保存しない (つまり、を使用するFoo m_foo;) と問題が解決することは理解していますが、これがなぜなのかわかりません。

さらに困惑するのは、リリース モードで実行している場合、上記のコードが目的どおりに機能することです。

Visual Studio 2010 を使用してコンパイルしています。

よろしくお願いします!

4

3 に答える 3

2

コンストラクタ Bar() のエラーを報告するコンパイラはほとんどありません。コンパイル中に以下のエラーが発生しました。

コンストラクター 'Bar::Bar()': タイプ 'Foo&' の一時的な非 const 参照の無効な初期化 タイプ 'Foo' コンパイルが原因で終了しました -Wfatal-errors

Bar() : m_foo(Foo()) { };

コンストラクター Bar では、Foo() はスタックに作成されたオブジェクトを返し、コンストラクターが戻るとその有効期間は終了します。したがって、その寿命は一時的なものであり、未定義のメモリへのアクセスやダングリング参照につながります。

解決策 1: 参照なしで Foo オブジェクトをそのまま使用する

class Bar
{
private:
   Foo m_foo;

public:
   Bar(){
};

void setFooValue(double value) {
    m_foo.setValue(value);
};

double getFooValue() {
    return m_foo.getValue();
};
};    

解決策 2: Foo オブジェクトをパラメーターとして Bar コンストラクターに渡します。これは main のスコープまで有効です。

class Bar
{
private:
    Foo &m_foo;

public:
    Bar(Foo &x) : m_foo(x) {
};

void setFooValue(double value) {
    m_foo.setValue(value);
};

double getFooValue() {
    return m_foo.getValue();
};
};    

int main()
{
Foo x;
Bar bar(x);

bar.setFooValue(10000.0);

double value = bar.getFooValue();

std::cout << "Foo value is: " << value << std::endl;
}
于 2013-04-12T10:07:00.213 に答える