3

我在我的项目中使用 Loki::Functor 来构建一个简单的事件系统。该事件的处理函数采用一些参数。在这种情况下,它被称为PrintEventString。为了将它放入队列中,事件处理程序必须具有相同的原型——在我的例子中,void func(void). 所以CreateEvent获取处理程序,从中创建函子并绑定参数,从而产生void f (void)原型。一切正常(第一个示例,字符串存储在局部变量中),直到我在调用仿函数之前销毁数据源(第二个示例,临时创建的字符串)。这是代码:

#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,内存错误检测器
==30296== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==30296== 使用 Valgrind-3.6.1 和 LibVEX;使用 -h 重新运行以获取版权信息
==30296== 命令:./main
==30296==
测试:你好世界
==30296== 大小为 4 的读取无效
==30296== 在 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== 由 0x8048E7A: 主 (main.cpp:26)
==30296== 地址 0x42f2640 在大小为 24 的块中是 8 个字节
==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&) (在 /usr/lib/libstdc++.so.6.0.16 中)
==30296== by 0x41A0232: (低于 main) (in /lib/libc-2.14.so)
==30296==
==30296== 大小为 4 的读取无效
==30296== 在 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== 由 0x8048E7A: 主 (main.cpp:26)
==30296== 地址 0x42f263c 在大小为 24 的块内有 4 个字节已释放
==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&) (在 /usr/lib/libstdc++.so.6.0.16 中)
==30296== by 0x41A0232: (低于 main) (in /lib/libc-2.14.so)
==30296==
==30296== 大小为 4 的读取无效
==30296== 在 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== 由 0x8048E7A: 主 (main.cpp:26)
==30296== 地址 0x42f2638 是大小为 24 的块内的 0 个字节 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&) (在 /usr/lib/libstdc++.so.6.0.16 中)
==30296== by 0x41A0232: (低于 main) (in /lib/libc-2.14.so)
==30296==
==30296== 大小为 4 的读取无效
==30296== 在 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== 由 0x8048E7A: 主 (main.cpp:26)
==30296== 地址 0x42f2638 是大小为 24 的块内的 0 个字节 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&) (在 /usr/lib/libstdc++.so.6.0.16 中)
==30296== by 0x41A0232: (低于 main) (in /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== 由 0x8048E7A: 主 (main.cpp:26)
==30296== 地址 0x42f264e 在大小为 24 的块内是 22 个字节
==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&) (在 /usr/lib/libstdc++.so.6.0.16 中)
==30296== by 0x41A0232: (低于 main) (in /lib/libc-2.14.so)
==30296==
==30296== 大小为 4 的读取无效
==30296== 在 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== 由 0x8048E7A: 主 (main.cpp:26)
==30296== 地址 0x42f2648 在大小为 24 的块内是 16 个字节
==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&) (在 /usr/lib/libstdc++.so.6.0.16 中)
==30296== by 0x41A0232: (低于 main) (in /lib/libc-2.14.so)
==30296==
==30296== 大小为 4 的读取无效
==30296== 在 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== 由 0x8048E7A: 主 (main.cpp:26)
==30296== 地址 0x42f2638 是大小为 24 的块内的 0 个字节 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&) (在 /usr/lib/libstdc++.so.6.0.16 中)
==30296== by 0x41A0232: (低于 main) (in /lib/libc-2.14.so)

我怀疑函子只引用传递的对象,然后将其销毁(作为临时创建的)并且问题开始了。但是我在这里做错了什么?我认为绑定将用于存储环境的一部分(正如安德烈在他的书中所描述的那样),以便可以破坏环境。

4

1 回答 1

1

问题是 Loki 的仿函数对象并没有制作字符​​串的真实副本,而是存储对您希望绑定到函数的字符串对象的引用。这是因为如果被绑定的参数的类型不是指针、成员指针或算术类型(即,您可以执行算术运算的类型),则 loki 的仿函数对象存储引用类型。因此,由于字符串是临时的,并且只存储了对临时的引用,一旦堆栈从函数调用中展开,对临时字符串的访问就会从活页夹对象的内部引用中丢失,并且您无法打印细绳。

One possible solution could be to create your function so that it takes a smart pointer type so that you can allocate an object dynamically, and the lifetime of the object will extend beyond the current scope, but avoid the issues surrounding object lifetime and memory leaks that would take place with a normal or naked pointer type.

Edit: I tried that out ... still doesn't seem to work as it's again storing a reference to the smart pointer type, and that means the pointer gets deallocated when the temporary smart pointer goes out-of-scope. So yes, you're either going to have to change some definitions of how loki's functor object determines whether to store a reference or a value, or use another version of binding arguments to function objects like the new C++11 standard's version of std::bind and std::function

于 2011-09-04T18:24:50.663 回答