8

私の経験から、次のいずれかのようです。

  • 関数呼び出し内で作成されたラムダ式は、呼び出しの直後に破棄されます
  • を期待する関数を呼び出すstd::functionと、ラムダから一時オブジェクト(std :: function)が作成され、そのオブジェクトは呼び出し後に破棄されます

この動作は、次のコードスニペットで確認できます。

const function<void()>* pointer;

void a(const function<void()> & f)
{
    pointer = &f;
}

void b()
{
    (*pointer)();
}

int main()
{
    int value = 1;
    std::cout << &value << std::endl;

    // 1: this works    
    function<void()> f = [&] () { std::cout << &value << std::endl; };
    a(f);

    // 2: this doesn't
    a([&] () { std::cout << &value << std::endl; });

    /* modify the stack*/
    char data[1024];
    for (int i = 0; i < 1024; i++)
        data[i] = i % 4; 

    b();

    return 0;
}

2番目のケースで実際に何が起こっているのでしょうか。a()明示的なstd::functionオブジェクトを作成せずに呼び出す正しい方法はありますか?

編集::この両方のバージョン(1と2)は正しくコンパイルされますが、出力が異なります。

バージョン1:

0x7fffa70148c8
0x7fffa70148c8

バージョン2:

0x7fffa70148c8
0
4

3 に答える 3

3

一時的なものを作成すると、行の最後で削除されます。これは、あなたが正しく述べたように、それへのポインタを保存することは悪い考えであることを意味します。

std::function(または実際には他の何か)へのポインタを格納する場合は、ポインタの使用を停止する前に、その存続期間が終了しないことを確認する必要があります。これは、タイプがの名前付きオブジェクトが本当に必要であることを意味しますstd::function

2番目のケースで何が起こっているかについて:関数に渡される一時的なラムダを作成します。関数はを期待するため、ラムダからstd::function一時的なものが作成されます。std::functionそれらの両方は、行の終わりに破壊されます。したがって、すでに破棄されている一時オブジェクトへのポインタがあります。つまり、ポイントされたオブジェクトを使用しようとすると、未定義の動作領域にしっかりと移動します。

于 2012-12-09T15:20:31.567 に答える
1

ステートレスラムダでも問題ありません。ステートレスラムダには、関数ポインター型への暗黙の変換があります。

また、実際の呼び出し可能タイプに関係なく、std ::function<>への暗黙の変換が常にあります。

ただし、一時的なものへのポインタを保持することには問題があります。コードを最初に読んだとき、私はそれに気づいていませんでした。

もちろん、それはstd::functionとは何の関係もありません。

于 2012-12-09T15:06:31.380 に答える
0

一時オブジェクトは、それらが作成されたステートメントの最後で破棄されます。ラムダを使用してこれを示したところです。

最初に渡すstd関数は一時的なものではないため、変数と同じ長さです。実際には一時的なもののコピーを保存します。

ラムダを1行以上持続させるには、ラムダをどこかに保管し、寿命を決定する必要があります。

これを行うには多くの方法があります。Std関数は、型消去に基づいて保存を行う方法です。つまり、std関数へのポインターの代わりにstd関数を保存します。タイプをpointer非ポインター(および非const)に変更し&、それに割り当てるときにを削除して、直接呼び出します。

一般に、別のオーバーロードで右辺値参照の可能性をキャッチしない限り、const参照関数パラメーターのアドレスをそれらへの一時的なバインドとして取得および保存することは避けてください。

于 2012-12-09T16:05:00.377 に答える