考虑以下代码:
#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_
并在方法内部检查它,这可能在解除分配后被调用。但是,我怀疑,它也不可靠。
更新(来自评论):
我需要此解决方法的真正原因是将函数作为参数的库。这个库是异步操作的,我无法控制传递给它的函数对象。这就是为什么当我的对象被释放时,库仍然可以使用最初传递的函数来调用回调,这会导致崩溃。
答案 0 :(得分:3)
您的对象由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
答案 1 :(得分:1)
您可以创建一个包含函数指针和shared_ptr
的对象的类。对象的shared_ptr
保证在破坏函数类之前不会销毁对象。
答案 2 :(得分:1)
Sulution 1)使用weak_ptr + lambda(几乎与 b4hand 相同,但它不会强迫你的班级活着)
从std :: enable_shared_from_this
继承你的类class X : public enable_shared_from_this<X>
并将getSomeFunc更改为以下内容:
SomeFunc getSomeFunc()
{
weak_ptr<X> weak = shared_from_this();
return [weak, this](const int& a){
shared_ptr<X> shared = weak.lock();
if (shared)
{
this->someMethod(a);
}
};
}
输出:
ctor Object
Object some method with 1
dtor Object
解决方案2)有点疯狂的代码+ lambda
如果您不能或不想使用共享/弱ptrs,您可以这样做:
#include <memory>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <set>
using namespace std;
typedef function<void(const int&)> SomeFunc;
class X {
private:
static set<X*> _aliveInstanties;
public:
X(string name) :name_(name)
{
_aliveInstanties.insert(this);
cout << "ctor " << name_ << endl;
}
~X()
{
_aliveInstanties.erase(_aliveInstanties.find(this));
cout << "dtor " << name_ << endl;
name_ = "empty";
}
SomeFunc getSomeFunc()
{
return [this](const int& a)
{
if (_aliveInstanties.find(this) != _aliveInstanties.end())
{
this->someMethod(a);
}
};
}
private:
string name_;
void someMethod(const int& a)
{
cout << name_ << " some method with " << a << endl;
}
};
答案 3 :(得分:0)
不使用lambda的另一个解决方案是从enable_shared_from_this
派生并在shared_from_this
方法中传递getSomeFunc
:
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()
{
return bind(&X::someMethod, shared_from_this(), _1);
}
private:
string name_;
void
someMethod(const int& a)
{
cout << name_ << " some method with " << a << endl;
}
};
但是,这将保留对象,直到释放所有回调。