Bearbeiten: Nachdem ich diese Antwort ein wenig mehr (mit Charles Bailey) diskutiert habe, glaube ich, dass dies unsicher ist, da es auf die Implementierung von boost :: function ankommt.
Der Call-Stack, wenn wir actual_foo geben wird wie folgt aussehen:
actual_foo
boost::function::operator()
main
Also, wenn actual_foo Ausführung beendet hat, werden wir wieder in den operator()
Code von boost::function
springen, und das Objekt gelöscht wurde. Dies ist nicht garantiert ein Problem zu sein - es ist ein bisschen wie delete this
aufrufen - aber Sie müssen sehr vorsichtig sein, was Sie in einer Member-Funktion eines gelöschten Objekts tun. Sie dürfen keine virtuellen Funktionen aufrufen oder Datenelemente verwenden.
Das Problem ist, dass ich nicht bewusst bin, dass boost::function
macht keine Garantien über das, was es in operator()
nach der Funktion es Wraps hat aufgerufen wurde. Es scheint auf meiner Plattform, dass es nichts Gefährliches tut (also beschweren sich Valgrind nicht), aber es ist durchaus vorstellbar, dass es auf einer anderen Plattform, mit einer anderen Implementierung oder mit verschiedenen Compiler-Flags etwas tun möchte, was nicht stimmt 't erlaubt, sobald das Objekt gelöscht wurde - zum Beispiel könnte es einige Debug-Informationen mit einer Member-Variable schreiben.
Also ich glaube, das ist eine gefährliche Sache zu tun, die unter bestimmten Umständen zu undefiniertem Verhalten führen kann.
Weitere Anmerkung:
nahm ich einen kurzen Blick auf, was Auftrieb wirklich tut, nachdem er den Funktionszeiger aufruft. Sieht man sich hier an: http://boost.cvs.sourceforge.net/viewvc/boost/boost/boost/function/function_template.hpp?view=markup an der operator() -Funktion in Zeile 687, meine Interpretation ist, dass es sofort den Rückgabewert zurückgibt und nichts anderes tut, also in der Praxis sollte man mit dieser Implementierung in Ordnung sein, aber die Kommentare dazu Sei gefährlich noch halt. Beachten Sie, dass ich sehr gut das falsche Stück Code gefunden haben, und/oder verstanden es falsch ...
Ursprüngliche Antwort unten:
Ich glaube, das ist ok. Wenn Sie actual_foo
eingeben, haben die Objekte boost::bind
und boost::function
ihre Jobs beendet, und Sie führen die echte Funktion actual_foo
aus.
Ich überprüfte dies auf meiner Plattform (gcc 4.2.4, Linux) durch Ausführen des Programms durch valgrind.Hier
ist das Programm, das ich lief:
#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);
}
und hier ist die valgrind Ausgang:
$ 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.
muss ich sagen aber, dass dies eine seltsame Sache scheint zu tun. Es wäre mir viel lieber, wenn es möglich wäre, das Funktionsobjekt automatisch zu löschen, indem man es zu einer Stapelvariablen macht, oder es im Destruktor einer Stapelvariablen zu löschen (wie in RAII). Es wäre sauberer, sicherer, weniger gruselig und ausnahmesicher. Aber ich bin mir sicher, dass Sie das alles bereits wissen, und es gibt gute Gründe, mit dem Code zu leben, wie er ist.
Zusammenfassung, kann es gefährlich sein abhängig davon, was der Operator() Aufruf in der Implementierung tut . Sie haben keine Garantie, was es tut, also nehmen Sie an, es ist gefährlich. Die aktuelle Implementierung von boost :: function wäre sicher. –