2017-03-07 10 views
12

私はstd::functionを指しています。この関数の中で、ポインタを別の関数に変更します。呼び出された関数の中でfunctionpointer(std :: function)を変更するのは安全ですか?

std::function<void()> fun; 

void foo() { 
    std::cout << "foo\n"; 
} 

void bar() { 
    std::cout << "bar\n"; 
    fun = foo; 
} 

int main() { 
    fun = bar; 
    fun(); 
    fun(); 
} 

しかし、私はそうする合法であるかどうかわからないんだけど、(hereを参照してください)私は何の問題を見ることができないと、それだけで正常に動作します。私はそうしたくないことがありますか(おそらくC++標準のドラフト(私はすぐにチェックしましたが、これまで何も見ませんでした))?

+6

これは何も問題はありません。それでおしまい。 –

+1

法的ではあるが、スタイルが悪い。グローバル変数の状態を制御するのが難しいため(これは避けようとするべきである)。 – Aziuth

+0

私はメインループコールバック(60回/秒と呼ばれる)として 'std :: function'を使用し、ゲーム状態(メニューの選択、再生、一時停止など)を変更するためのさまざまなメソッドに割り当てるミニゲームプロジェクトを持っています。それは正常に動作します。 – tntxtnt

答えて

10

これは関数ポインタでは正当です。

std::functionにターゲットを割り当てまたは構成すると、コピーのターゲットが作成されます。 std::functionに関数を代入する場合、実際には関数ポインタを対象オブジェクトとして格納します。

operator()を呼び出すときは、引数を指定してターゲットを呼び出すとどうなるかを返す必要があります。

std::functionにコピーとして格納されている関数オブジェクトのコピーの "本体"内に、std::functionに再割り当てすると、これは古いターゲット関数オブジェクトを破壊します。

関数ポインタを破棄しても、その関数内で実行されたコードの有効性には影響しません。あなたが関数にオブジェクト(ラムダ、手動のもの、他のstd::function S、std::bindなど)を格納していた場合

しかし、割り当ての時点で、あなたはときに、クラスでメソッドを実行しているの通常の規則に遭遇するだろうthisが破壊されました。要するに、インスタンスの「ローカル状態」に依存するものは、もはや実行できません。

std::function<void()> fun; 
struct bob { 
    std::string name; 
    bob* next = 0; 
    void operator()() const { 
    std::cout << name << "\n"; 
    if (next) fun = *next; 
    // undefined behavior: 
    // std::cout << name << "\n"; 
    } 
}; 
bob foo = {"foo"}; 
bob bar = {"bar", &foo}; 

int main() { 
    fun = bar; 
    fun(); 
    fun(); 
} 

live example

ご覧のとおり、これは壊れやすい可能性があります。

-1

あなたがそれを考慮しなくても、コードの文書でそれを行うなら、それはあなたに噛み付くかもしれませんが、それがうまくいかない理由はありません。

C++では、戻りコードの関数内でも関数のアドレスは必要ありません。

一部の言語ではうまくいかなかった場合、おそらくコンパイラはそれを受け入れないでしょう。

+2

最後の文章に一般には同意しません。別のケースでは、プログラマが望むようにコンパイラが処理できる未定義の動作かもしれないが、まだ未定義である。 – Aziuth

+0

ハーフデシェントコンパイラは、動作が未定義の場合があるものを受け付けません。 Cコンパイラが何年も前に、最も恐ろしいコードを受け取りました。幸運なことに、ほとんどのC++コンパイラは非常に厳しいものです。 – Quandon

+0

まあまあコンパイラは '* nullptr'をコンパイルできるようにします... – YSC

関連する問題