考虑这段代码:
#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;
typedef function<void(const int&)> SomeFunc;
class X {
public:
X(string name):name_(name)
{ cout << "ctor " << name_ << endl; }
~X()
{
cout << "dtor " << name_ << endl;
name_ = "empty";
}
SomeFunc
getSomeFunc()
{ return bind(&X::someMethod, this, _1); }
private:
string name_;
void
someMethod(const int& a)
{
cout << name_ << " some method with " << a << endl;
}
};
int main()
{
SomeFunc f;
{
shared_ptr<X> x(new X("Object"));
f = x->getSomeFunc();
f(1);
}
f(2);
return 0;
}
有时,输出会给我这个:
ctor Object
Object some method with 1
dtor Object
empty some method with 2
其他时候:
ctor Object
Object some method with 1
dtor Object
some method with 2
在现实世界中,一旦释放的对象尝试访问它的属性,它很可能会让我崩溃。 所以这里有一个问题 - 由于函数不能保证保留对其所指向的对象的引用,因此在引用的对象已被释放后调用函数时避免崩溃的最佳实践是什么?
我可能想到的解决方案之一 - 在对象内部维护一个特殊的标志 bool deallocated_
,并在释放后可能调用的方法内部检查它。不过,我怀疑它也不可靠。
更新(来自评论):
我需要这个解决方法的真正原因是该库将函数作为参数。该库异步运行,我无法控制传递给它的函数对象。这就是为什么当我的对象被释放时,库仍然可以使用最初传递的函数调用回调,从而导致崩溃。
最佳答案
您的对象由 shared_ptr
持有,因此您可以使用 lambda 来关闭 shared_ptr
:
auto func = [ptr](const int &p){ ptr->someMethod(p); };
您需要使用 shared_from_this
在类中获取 ptr
。
这是一个完整的示例:
#include <iostream>
#include <functional>
#include <memory>
using namespace std;
using namespace std::placeholders;
typedef function<void(const int&)> SomeFunc;
class X : public enable_shared_from_this<X> {
public:
X(string name) : name_(name) {
cout << "ctor " << name_ << endl;
}
~X() {
cout << "dtor " << name_ << endl;
name_ = "empty";
}
SomeFunc getSomeFunc() {
auto ptr = shared_from_this();
return [ptr](const int &a){ ptr->someMethod(a); };
}
private:
string name_;
void someMethod(const int& a) {
cout << name_ << " some method with " << a << endl;
}
};
int main()
{
SomeFunc f;
{
shared_ptr<X> x(new X("Object"));
f = x->getSomeFunc();
f(1);
}
f(2);
return 0;
}
输出如下所示:
ctor Object
Object some method with 1
Object some method with 2
dtor Object
关于c++ - 调用指向已释放对象方法的 std::function 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28080183/