编辑:在讨论了这个答案之后(与查尔斯贝利),我认为这是不安全的,因为它取决于 boost::function 的实现。
当我们输入 actual_foo 时的调用堆栈将如下所示:
actual_foo
boost::function::operator()
main
所以当 actual_foo 执行完毕后,我们会跳回到 的operator()
代码中boost::function
,这个对象已经被删除了。这不保证是一个问题——它有点像调用delete this
——但你必须非常小心你在一个已删除对象的成员函数中所做的事情。你不能调用任何虚函数或使用任何数据成员。
问题是我不知道在调用它包装的函数之后boost::function
它会做什么保证。operator()
似乎在我的平台上它没有做任何危险的事情(所以 valgrind 不会抱怨),但完全可以想象,在不同的平台上,使用不同的实现或不同的编译标志,它可能想做一些不'一旦对象被删除就不允许 - 例如,它可能会使用成员变量写出一些调试信息。
因此,我认为这是一件危险的事情,在某些情况下可能会导致未定义的行为。
进一步说明:
在调用函数指针之后,我快速查看了 boost 的真正作用。看这里:http://boost.cvs.sourceforge.net/viewvc/boost/boost/boost/function/function_template.hpp?view=markup在第 687 行的 operator() 函数中,我的解释是它立即返回返回值并且不做任何其他事情,因此在实践中,通过该实现,您应该没问题,但是关于它的评论仍然很危险。请注意,我很可能发现了错误的代码和/或理解错误......
原答案如下:
我相信这没问题。当你进入actual_foo
时,boost::bind
和boost::function
对象已经完成了它们的工作,你正在执行真正的函数actual_foo
。
我通过valgrind运行程序在我的平台(gcc 4.2.4,Linux)上检查了这一点。
这是我运行的程序:
#include <boost/bind.hpp>
#include <boost/function.hpp>
class Magic
{
public:
int magic( int i )
{
return 5;
}
};
typedef boost::function<int(int)> foo_type;
foo_type* global_foo = NULL;
int actual_foo( int i, Magic* m )
{
delete global_foo;
return m->magic(i);
}
int main()
{
Magic m;
global_foo = new foo_type( boost::bind( &actual_foo, _1, &m ) );
return (*global_foo)(10);
}
这是 valgrind 的输出:
$ valgrind ./boost_bind
==17606== Memcheck, a memory error detector.
==17606== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==17606== Using LibVEX rev 1804, a library for dynamic binary translation.
==17606== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==17606== Using valgrind-3.3.0-Debian, a dynamic binary instrumentation framework.
==17606== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==17606== For more details, rerun with: -v
==17606==
==17606==
==17606== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 17 from 1)
==17606== malloc/free: in use at exit: 0 bytes in 0 blocks.
==17606== malloc/free: 1 allocs, 1 frees, 16 bytes allocated.
==17606== For counts of detected errors, rerun with: -v
==17606== All heap blocks were freed -- no leaks are possible.
不过,我必须说,这似乎是一件奇怪的事情。如果可能的话,我更愿意通过将其设为堆栈变量或在堆栈变量的析构函数中将其删除(如RAII中)来使用此函数对象的自动删除。它会更整洁、更安全、更不可怕、更安全。但我相信您已经知道所有这些,并且有充分的理由使用代码。