2011-09-04 26 views
3

我在我的項目中使用Loki :: Functor進行簡單的事件系統。該事件的處理函數需要一些參數。在這種情況下,它被稱爲PrintEventString。爲了將它放入隊列中,事件處理程序必須具有相同的原型 - 在我的例子中,void func(void)。因此CreateEvent需要處理程序,從它創建函子並綁定參數,從而產生void f (void)原型。一切都很順利(第一個例子是存儲在本地變量中的字符串),直到我在調用函數之前銷燬數據源(第二個示例,臨時創建的字符串)。下面是代碼:Loki函子 - 內存問題

#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; 
} 

這將編譯,執行,但第二次測試簡化版,工作和Valgrind的拋出一堆錯誤:

 
==30296== Memcheck, a memory error detector 
==30296== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. 
==30296== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info 
==30296== Command: ./main 
==30296== 
Test: Hello world 
==30296== Invalid read of size 4 
==30296== at 0x40EB655: std::basic_string, std::allocator >::basic_string(std::string const&) (in /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 (main.cpp:26) 
==30296== Address 0x42f2640 is 8 bytes inside a block of size 24 free'd 
==30296== at 0x4026B2C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x41A0232: (below main) (in /lib/libc-2.14.so) 
==30296== 
==30296== Invalid read of size 4 
==30296== at 0x40EAD96: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (in /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 (main.cpp:26) 
==30296== Address 0x42f263c is 4 bytes inside a block of size 24 free'd 
==30296== at 0x4026B2C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x41A0232: (below main) (in /lib/libc-2.14.so) 
==30296== 
==30296== Invalid read of size 4 
==30296== at 0x40EADA5: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (in /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 (main.cpp:26) 
==30296== Address 0x42f2638 is 0 bytes inside a block of size 24 free'd 
==30296== at 0x4026B2C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x41A0232: (below main) (in /lib/libc-2.14.so) 
==30296== 
==30296== Invalid read of size 4 
==30296== at 0x40EADB3: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (in /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 (main.cpp:26) 
==30296== Address 0x42f2638 is 0 bytes inside a block of size 24 free'd 
==30296== at 0x4026B2C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x41A0232: (below main) (in /lib/libc-2.14.so) 
==30296== 
==30296== Invalid read of size 1 
==30296== at 0x40294BA: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40EADF7: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x40EB68F: std::basic_string, std::allocator >::basic_string(std::string const&) (in /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 (main.cpp:26) 
==30296== Address 0x42f264e is 22 bytes inside a block of size 24 free'd 
==30296== at 0x4026B2C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x41A0232: (below main) (in /lib/libc-2.14.so) 
==30296== 
==30296== Invalid read of size 4 
==30296== at 0x40294E8: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40EADF7: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x40EB68F: std::basic_string, std::allocator >::basic_string(std::string const&) (in /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 (main.cpp:26) 
==30296== Address 0x42f2648 is 16 bytes inside a block of size 24 free'd 
==30296== at 0x4026B2C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x41A0232: (below main) (in /lib/libc-2.14.so) 
==30296== 
==30296== Invalid read of size 4 
==30296== at 0x40EADF8: std::string::_Rep::_M_clone(std::allocator const&, unsigned int) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x40EB68F: std::basic_string, std::allocator >::basic_string(std::string const&) (in /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 (main.cpp:26) 
==30296== Address 0x42f2638 is 0 bytes inside a block of size 24 free'd 
==30296== at 0x4026B2C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==30296== by 0x40E9C7A: std::string::_Rep::_M_destroy(std::allocator const&) (in /usr/lib/libstdc++.so.6.0.16) 
==30296== by 0x41A0232: (below main) (in /lib/libc-2.14.so) 

我懷疑仿函數僅取一個參考傳遞的對象,然後被銷燬(如臨時創建)並且問題開始。但是我在這裏做錯了什麼?我認爲綁定是用來存儲部分環境的(正如Andrei在他的書中所描述的那樣),這樣環境就可以被破壞。

+0

您能否在Loki的版本上添加更多信息以及如何編譯源代碼?它不在這裏編譯,因爲我的Loki版本使用'LOKI_TYPELIST_1'而不是'TYPELIST_1'。 – evnu

+0

@evnu:我有本書提供的鏈接的正式版本。我能看到的唯一版本是最後的庫更新:2001年6月20日 –

+0

項目網站http://loki-lib.sourceforge.net/在http://sourceforge.net/projects/loki-lib/files下列出了更多版本/ Loki/ – evnu

回答

1

問題是Loki的functor對象沒有製作字符​​串的真實副本,而是存儲了一個對字符串對象的引用,您希望將其綁定到您的函數。這是因爲如果被綁定參數的類型不是指針,成員指針或算術類型(即可以執行算術運算的類型),則loki的functor對象會存儲引用類型。因此,由於該字符串是臨時的,並且只存儲臨時文件的引用,所以一旦堆棧從函數調用中解開,臨時字符串的訪問將從活頁夾對象中的內部引用中丟失,並且無法打印串。

一個可能的解決方案可能是創建您的函數,以便它採用智能指針類型,以便您可以動態分配對象,並且該對象的生命週期將超出當前範圍,但避免周圍對象生命週期的問題以及使用正常或裸指針類型發生的內存泄漏。

編輯:我試過了...似乎仍然沒有工作,因爲它再次向存儲智能指針類型的引用,這意味着當臨時智能指針超出-的指針被釋放-範圍。所以是的,你要麼必須改變一些關於loki的函數對象如何決定是存儲一個引用還是一個值的定義,要麼使用另一個綁定參數版本來作爲函數對象,如新的C++ 11標準版本std::bindstd::function

+0

謝謝,我認爲這是這樣的。我喜歡Loki :: Functor,因爲它使用簡單。現在,當我需要自己處理深層複製時,我可能會堅持使用std :: tr1。我測試了它(說實話,我甚至不知道std有這樣的東西),它更合適(因爲它似乎在綁定時使用深拷貝)。 –