Loki函子 - 内存的问题 [英] Loki functor - problem with memory

查看:174
本文介绍了Loki函子 - 内存的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的项目中使用Loki :: Functor作为一个简单的事件系统。事件的处理函数采用一些参数。在这种情况下,它被称为 PrintEventString 。为了把它放入队列,事件处理程序必须具有相同的原型 - 在我的例子中, void func(void)。因此 CreateEvent 接受处理程序,从中创建functor并绑定参数,导致 void f(void)原型。一切都很好(第一个例子,字符串存储在局部变量),直到我在调用functor之前破坏数据源(第二个例子,临时创建的字符串)。这里是代码:

I use Loki::Functor in my project for a simple event system. The event has its handler function taking some parameters. In this case, it is called PrintEventString. In order to put it in the queue, the event handlers must have same prototypes - in my case, void func(void). So CreateEvent takes the handler, creates functor from it and binds the parameter, resulting in void f (void) prototype. Everything goes fine (first example with string stored in local variable), until I destroy the data source before calling functor (second example, string created temporarily). Here is the code:

#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抛出一堆错误:

This compiles, executes, but the second test does't work and valgrind throws a bunch of errors:


==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在他的书中描述的),以便环境可以被销毁。

I suspect the functor to take only a reference to passed object, which is then destroyed (as temporarily created) and the problems begin. But what am I doing wrong here? I supposed the binding is to be used for storing part of the environment (as Andrei describes in his book), so that the environment can be destroyed.

推荐答案

问题是,Loki的functor对象不是一个真正的字符串副本,而是存储对字符串对象的引用,你想绑定到你的函数。这是因为如果被绑定的参数的类型不是指针,成员指针或算术类型(即,可以用其执行算术运算的类型),loki的functor对象存储引用类型。因此,由于字符串是一个临时的,并且只有临时的引用被存储,一旦堆栈从函数调用中解开,访问临时字符串从binder对象中的内部引用丢失,并且您无法打印字符串。

The problem is that Loki's functor object is not making a true copy of the string, but rather is storing a reference to the string object that you are wanting to have bound to your function. This is because loki's functor object stores a reference type if the type of the argument being bound is not a pointer, member pointer, or arithmetic type (i.e., a type you can perform an arithmetic operation with). So since the string is a temporary, and only a reference to the temporary is stored, once the stack unwinds from the function call, access to the temporary string is lost from the internal reference in the binder object, and you are unable to print the string.

一个可能的解决方案可能是创建你的函数,使它需要一个智能指针类型,以便你可以动态分配一个对象,扩展超出当前范围,但避免了使用正常或裸露指针类型发生的关于对象生命周期和内存泄漏的问题。

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.

编辑:我试过了...仍然似乎不工作,因为它再次存储对智能指针类型的引用,这意味着当临时智能指针超出范围时,指针被释放。所以是的,你要不得不改变一些定义,如何loki的函子对象确定是否存储引用或值,或使用绑定参数的另一个版本的函数对象,如新的C ++ 11标准的版本 std :: bind std :: function

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

这篇关于Loki函子 - 内存的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆