gpt4 book ai didi

c++ - Loki 仿函数 - 内存问题

转载 作者:行者123 更新时间:2023-12-02 02:26:07 25 4
gpt4 key购买 nike

我在项目中使用 Loki::Functor 来构建简单的事件系统。该事件的处理函数带有一些参数。在本例中,它称为 PrintEventString。为了将其放入队列中,事件处理程序必须具有相同的原型(prototype) - 在我的例子中,void func(void)。因此,CreateEvent 接受处理程序,从中创建仿函数并绑定(bind)参数,从而产生 void f (void) 原型(prototype)。一切都很顺利(第一个示例,字符串存储在局部变量中),直到我在调用仿函数之前销毁数据源(第二个示例,临时创建的字符串)。这是代码:

#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)

我怀疑仿函数仅获取对传递对象的引用,然后该对象被销毁(作为临时创建的)并且问题开始了。但我在这里做错了什么?我认为绑定(bind)是用来存储部分环境的(正如Andrei在他的书中描述的那样),这样环境就可以被破坏。

最佳答案

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

一种可能的解决方案是创建函数,使其采用智能指针类型,以便您可以动态分配对象,并且对象的生命周期将超出当前范围,但避免围绕对象生命周期和普通或裸指针类型会发生内存泄漏。

编辑:我尝试过......似乎仍然不起作用,因为它再次存储对智能指针类型的引用,这意味着当临时智能指针时指针被释放超出范围。所以,是的,您要么必须更改 loki 仿函数对象如何确定是否存储引用还是值的一些定义,要么使用另一个版本的将参数绑定(bind)到函数对象,例如新的 C++11 标准版本的 std::bindstd::function

关于c++ - Loki 仿函数 - 内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7299166/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com