3

私のプロジェクトでは、単純なイベント システムに Loki::Functor を使用しています。イベントには、いくつかのパラメーターを受け取るハンドラー関数があります。この場合は と呼びPrintEventStringます。キューに入れるには、イベント ハンドラーに同じプロトタイプ (私の場合はvoid func(void). したがってCreateEvent、ハンドラーを受け取り、そこからファンクターを作成し、パラメーターをバインドして、void f (void)プロトタイプを作成します。functor を呼び出す前にデータ ソースを破棄するまで (2 番目の例、一時的に作成された文字列)、すべてがうまくいきます (ローカル変数に格納された文字列を使用する最初の例)。コードは次のとおりです。

#include <climits>
#include <string>
#include <iostream>
#include "Loki/Functor.h"

void PrintEventString(std::string str)
{
    std::cout << "Test: " << str << std::endl;
}

Loki::Functor<void> CreateEvent (std::string str)
{
    Loki::Functor<void, TYPELIST_1(std::string)> handler(PrintEventString);
    Loki::Functor<void> event (Loki::BindFirst(handler, str));
    return event;
}

int main (void)
{
    std::string hello("hello");

    Loki::Functor<void> eventTestLocal(CreateEvent(hello));
    eventTestLocal();

    Loki::Functor<void> eventTestTemp(CreateEvent("Hello world"));
    eventTestTemp();


    return 0;
}

これはコンパイル、実行されますが、2 番目のテストは機能せず、valgrind は一連のエラーをスローします。

==30296== Memcheck、メモリエラー検出器
==30296== Copyright (C) 2002-2010、および Julian Seward らによる GNU GPL です。
==30296== Valgrind-3.6.1 と LibVEX を使用。著作権情報については -h で再実行してください
==30296== コマンド: ./main
==30296==
テスト: ハローワールド
==30296== サイズ 4 の無効な読み取り
==30296== at 0x40EB655: std::basic_string, std::allocator >::basic_string(std::string const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x8049C4F: Loki::Functor, Loki::SingleThreaded>::operator()(std::string&) (Functor.h:779)
==30296== by 0x8049B59: Loki::BinderFirst, Loki::SingleThreaded> >::operator()() (Functor.h:908)
==30296== by 0x80492D6: Loki::Functor::operator()() (Functor.h:776)
==30296== by 0x8048E7A: メイン (main.cpp:26)
==30296== アドレス 0x42f2640 は、解放されたサイズ 24 のブロック内の 8 バイトです
==30296== at 0x4026B2C: operator delete(void*) (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x41A0232: (メインの下) (/lib/libc-2.14.so 内)
==30296==
==30296== サイズ 4 の無効な読み取り
==30296== at 0x40EAD96: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x8049C4F: Loki::Functor, Loki::SingleThreaded>::operator()(std::string&) (Functor.h:779)
==30296== by 0x8049B59: Loki::BinderFirst, Loki::SingleThreaded> >::operator()() (Functor.h:908)
==30296== by 0x80492D6: Loki::Functor::operator()() (Functor.h:776)
==30296== by 0x8048E7A: メイン (main.cpp:26)
==30296== アドレス 0x42f263c は、解放されたサイズ 24 のブロック内の 4 バイトです
==30296== at 0x4026B2C: operator delete(void*) (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x41A0232: (メインの下) (/lib/libc-2.14.so 内)
==30296==
==30296== サイズ 4 の無効な読み取り
==30296== at 0x40EADA5: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x8049C4F: Loki::Functor, Loki::SingleThreaded>::operator()(std::string&) (Functor.h:779)
==30296== by 0x8049B59: Loki::BinderFirst, Loki::SingleThreaded> >::operator()() (Functor.h:908)
==30296== by 0x80492D6: Loki::Functor::operator()() (Functor.h:776)
==30296== by 0x8048E7A: メイン (main.cpp:26)
==30296== アドレス 0x42f2638 は、解放されたサイズ 24 のブロック内の 0 バイトです
==30296== at 0x4026B2C: operator delete(void*) (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x41A0232: (メインの下) (/lib/libc-2.14.so 内)
==30296==
==30296== サイズ 4 の無効な読み取り
==30296== at 0x40EADB3: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x8049C4F: Loki::Functor, Loki::SingleThreaded>::operator()(std::string&) (Functor.h:779)
==30296== by 0x8049B59: Loki::BinderFirst, Loki::SingleThreaded> >::operator()() (Functor.h:908)
==30296== by 0x80492D6: Loki::Functor::operator()() (Functor.h:776)
==30296== by 0x8048E7A: メイン (main.cpp:26)
==30296== アドレス 0x42f2638 は、解放されたサイズ 24 のブロック内の 0 バイトです
==30296== at 0x4026B2C: operator delete(void*) (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x41A0232: (メインの下) (/lib/libc-2.14.so 内)
==30296==
==30296== サイズ 1 の無効な読み取り
==30296== 0x40294BA: memcpy (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40EADF7: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x40EB68F: std::basic_string, std::allocator >::basic_string(std::string const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x8049C4F: Loki::Functor, Loki::SingleThreaded>::operator()(std::string&) (Functor.h:779)
==30296== by 0x8049B59: Loki::BinderFirst, Loki::SingleThreaded> >::operator()() (Functor.h:908)
==30296== by 0x80492D6: Loki::Functor::operator()() (Functor.h:776)
==30296== by 0x8048E7A: メイン (main.cpp:26)
==30296== アドレス 0x42f264e は、解放されたサイズ 24 のブロック内の 22 バイトです
==30296== at 0x4026B2C: operator delete(void*) (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x41A0232: (メインの下) (/lib/libc-2.14.so 内)
==30296==
==30296== サイズ 4 の無効な読み取り
==30296== at 0x40294E8: memcpy (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40EADF7: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x40EB68F: std::basic_string, std::allocator >::basic_string(std::string const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x8049C4F: Loki::Functor, Loki::SingleThreaded>::operator()(std::string&) (Functor.h:779)
==30296== by 0x8049B59: Loki::BinderFirst, Loki::SingleThreaded> >::operator()() (Functor.h:908)
==30296== by 0x80492D6: Loki::Functor::operator()() (Functor.h:776)
==30296== by 0x8048E7A: メイン (main.cpp:26)
==30296== アドレス 0x42f2648 は、解放されたサイズ 24 のブロック内の 16 バイトです
==30296== at 0x4026B2C: operator delete(void*) (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x41A0232: (メインの下) (/lib/libc-2.14.so 内)
==30296==
==30296== サイズ 4 の無効な読み取り
==30296== at 0x40EADF8: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x40EB68F: std::basic_string, std::allocator >::basic_string(std::string const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x8049C4F: Loki::Functor, Loki::SingleThreaded>::operator()(std::string&) (Functor.h:779)
==30296== by 0x8049B59: Loki::BinderFirst, Loki::SingleThreaded> >::operator()() (Functor.h:908)
==30296== by 0x80492D6: Loki::Functor::operator()() (Functor.h:776)
==30296== by 0x8048E7A: メイン (main.cpp:26)
==30296== アドレス 0x42f2638 は、解放されたサイズ 24 のブロック内の 0 バイトです
==30296== at 0x4026B2C: operator delete(void*) (/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so 内)
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (/usr/lib/libstdc++.so.6.0.16 内)
==30296== by 0x41A0232: (メインの下) (/lib/libc-2.14.so 内)

ファンクタが渡されたオブジェクトへの参照のみを取得すると思われます。オブジェクトは(一時的に作成されたものとして)破棄され、問題が発生します。しかし、ここで何が間違っているのでしょうか? 環境を破壊できるように、バインディングは環境の一部を保存するために使用されると思いました (Andrei が彼の本で説明しているように)。

4

1 に答える 1

1

問題は、Loki の functor オブジェクトが文字列の真のコピーを作成するのではなく、関数にバインドしたい文字列オブジェクトへの参照を格納していることです。これは、バインドされる引数の型がポインター、メンバー ポインター、または算術型 (つまり、算術演算を実行できる型) でない場合、loki のファンクター オブジェクトが参照型を格納するためです。したがって、文字列は一時的なものであり、一時的なものへの参照のみが格納されるため、スタックが関数呼び出しから巻き戻されると、バインダー オブジェクトの内部参照から一時的な文字列へのアクセスが失われ、ストリング。

考えられる解決策の 1 つは、オブジェクトを動的に割り当てることができるようにスマート ポインター型を取るように関数を作成することです。オブジェクトの有効期間は現在のスコープを超えて延長されますが、オブジェクトの有効期間とメモリ リークに関する問題は回避されます。通常または裸のポインター型で発生します。

編集:私はそれを試してみました...スマートポインタータイプへの参照を再び保存しているため、まだ機能していないようです。つまり、一時的なスマートポインターが範囲外になると、ポインターの割り当てが解除されます。そうです、loki の functor オブジェクトが参照または値を格納するかどうかを決定する方法の定義を変更するか、新しい C++11 標準のバージョンのstd::bindandのような関数オブジェクトへのバインド引数の別のバージョンを使用する必要があります。std::function

于 2011-09-04T18:24:50.663 に答える