1

以下のコード サンプルに似た型階層があり、ファクトリ パターンを介してインスタンス化しようとしています (または、ファクトリは XML ドキュメントから入力を取得するため、より詳しく言えばビルダー パターンを使用します... しかし、私は余談)。

しかし、私はこれをやろうとしていますが、値で返す場合はスライスするか、参照で返す場合はスコーピングが原因であると思われる問題に遭遇しています。

たとえば、以下のプログラムは、a.doA()内の行で segfault を実行しますC::doStuff()value_C_factory<C>()代わりにへの呼び出しを変更するとref_C_factory<C>()、「一時的な参照を返す」という警告がいくつか表示されますが、プログラムはコンパイルされ、代わりにb.doB()次の行でセグメンテーション違反が発生します (... から何も出力されa.doA()ません)。

からのバックトレースはgdb次のようになります - 2行目は、上記のコードの1行です

#0  0x00007ffff7dbddb0 in vtable for std::ctype<char> () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00000000004010e9 in C::doStuff (this=0x7fffffffdd00) at syntax.cpp:57
#2  0x0000000000400cf2 in main () at syntax.cpp:95

これらのセグメンテーション違反の原因は何ですか? 私が疑うように、値/参照ケースでのスライス/スコープですか? そうでない場合、それは何ですか? そして最も重要なのは、入力データからインスタンスを構築する良い方法は何ですか?

コードサンプル

以下のコードは、コンパイルして、たとえば GCC 4.8 を使用して上記の動作を提供する必要があります
gcc -g -Wall -std=c++11 -o test test.cpp(とにかく、それは私がしていることです)。

#include <iostream>
#include <typeinfo>

class IA {
public:
    virtual void doA() const = 0;
    virtual ~IA() { }
};

class A : public IA {
private:
    std::string atask;
public:
    explicit A(const std::string &task) : atask(task) {
        std::cout << "Created A with task " << atask << std::endl;
    }

    void doA() const {
        std::cout << "I did A! " << atask << std::endl;
    }
};

class IB {
public:
    virtual void doB() const = 0;
    virtual ~IB() { }
};

class B : public IB {
private:
    std::string btask;
public:
    explicit B(const std::string &task) : btask(task) {
        std::cout << "Created B with task " << btask << std::endl;
    }

    void doB() const {
        std::cout << "I did B! " << btask << std::endl;
    }
};

class IC {
public:
    void doStuff() const;
    virtual ~IC() { }
};

class C : public IC {
private:
    const IA &a;
    const IB &b;

public:
    C(const IA &a, const IB &b) : a(a), b(b) { }

    void doStuff() const {
        a.doA();    // with value factory method, segfault here
        b.doB();    // with reference factory, segfault here instead
    }
};

template<typename TA>
TA value_A_factory() {
    return TA("a value");
}

template<typename TB>
TB value_B_factory() {
    return TB("b value");
}

template<typename TC>
TC value_C_factory() {
    return TC(value_A_factory<A>(), value_B_factory<B>());
}


template<typename TA>
const TA &ref_A_factory() {
    return TA("a ref");
}

template<typename TB>
const TB &ref_B_factory() {
    return TB("b ref");
}

template<typename TC>
const TC &ref_C_factory() {
    const TC &c(ref_A_factory<A>(), ref_B_factory<B>());
    return c;
}

int main() {
    C c = value_C_factory<C>();
    std::cout << typeid(c).name() << std::endl;
    c.doStuff();
}
4

2 に答える 2

2

2 つの問題があり、どちらも未定義の動作が原因です。

1 つ目は、ローカル変数への参照を返すことができないことです。関数が戻り、ローカル変数がスコープ外に出て破棄されると、返された参照は何を参照しますか?

もう 1 つの問題は、一時的な値への参照を格納することです。関数によって返される値が一時的Cなようにクラスを作成すると、完全な式 ( ) が完了すると破棄されます。TC(value_A_factory<A>(), value_B_factory<B>())value_X_factoryTC(...)

于 2014-04-02T10:48:56.447 に答える