是否可以检测绑定成员函数引用的对象是否被删除或销毁
Is it possible to detect if the object that a bound member function refers to is deleted or destroyed
我正在探索 std::function
和 std::bind
的用法。我看到你可以绑定一个成员函数,例如:
class A{
int c_ = 10;
public:
int add(int a, int b){
return a + b + c_;
}
};
int main(){
A* p_a = new A;
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
delete p_a;
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
}
有没有办法检测 p_a 是否已被删除?
我的解决方案是使用一个包含函数的包装器 class 和一个对象的 weak_ptr
。我只是想知道是否有更优雅的方法来做到这一点。
std::bind
可以接受智能指针,所以你可以简单地传递 std::shared_ptr<A>
给它。
std::shared_ptr<A> p_a(new A);
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
注意,仿函数将拥有对象:只要仿函数存在,对象就会存在。如果您不想要这种行为,那么使用 weak_ptr
包装器的解决方案很好。
struct A{
int c_ = 10;
int add(int a, int b){
return a + b + c_;
}
};
template<class T>
std::weak_ptr<T> weak( std::shared_ptr<T> const& sp ) { return {sp}; }
int main(){
auto p_a = std::make_shared<A>();
std::function<int()> f = [w_a = weak(p_a)]() {
if (auto p_a = w_a.lock())
return p_a->add(1,1);
throw w_a;
}
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
p_a.reset();
try {
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
} catch( std::weak_ptr<A> wp ) {
printf("object deleted\n");
}
}
一般来说,在 C++ 中,您不需要为不使用的东西付费。
跟踪对象的生命周期是有代价的。如果要跟踪对象的生命周期,可以对(自由存储)分配的对象使用 shared_ptr
或 weak_ptr
,或者对 shared_ptr
使用 weak_ptr
(唯一)由对象拥有以指示其生命周期结束。
以上是使用 C++14 lambdas 捕获对象的共享指针作为弱指针的实现,如果它已被删除,则给出定义的行为(抛出所述弱指针的副本)。
终身令牌如下所示:
using lifetime_token = std::weak_ptr<void>;
struct has_lifetime {
has_lifetime():token(std::make_shared<char>()) {}
has_lifetime(has_lifetime const&o):has_lifetime() {} // not default
lifetime_token get_lifetime() const {
return token;
}
private:
std::shared_ptr<void> token;
};
从 has_lifetime
继承给你一个 get_lifetime()
成员,只要你这样做就存在(它被你的析构函数销毁,并且不再是 .lock()
d)。
如果您无法修改原始 class 的所有权语义,则此模式更容易遵循。只需 .lock()
对象的 lifetime_token
来确定它是否还活着。
我正在探索 std::function
和 std::bind
的用法。我看到你可以绑定一个成员函数,例如:
class A{
int c_ = 10;
public:
int add(int a, int b){
return a + b + c_;
}
};
int main(){
A* p_a = new A;
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
delete p_a;
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
}
有没有办法检测 p_a 是否已被删除?
我的解决方案是使用一个包含函数的包装器 class 和一个对象的 weak_ptr
。我只是想知道是否有更优雅的方法来做到这一点。
std::bind
可以接受智能指针,所以你可以简单地传递 std::shared_ptr<A>
给它。
std::shared_ptr<A> p_a(new A);
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
注意,仿函数将拥有对象:只要仿函数存在,对象就会存在。如果您不想要这种行为,那么使用 weak_ptr
包装器的解决方案很好。
struct A{
int c_ = 10;
int add(int a, int b){
return a + b + c_;
}
};
template<class T>
std::weak_ptr<T> weak( std::shared_ptr<T> const& sp ) { return {sp}; }
int main(){
auto p_a = std::make_shared<A>();
std::function<int()> f = [w_a = weak(p_a)]() {
if (auto p_a = w_a.lock())
return p_a->add(1,1);
throw w_a;
}
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
p_a.reset();
try {
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
} catch( std::weak_ptr<A> wp ) {
printf("object deleted\n");
}
}
一般来说,在 C++ 中,您不需要为不使用的东西付费。
跟踪对象的生命周期是有代价的。如果要跟踪对象的生命周期,可以对(自由存储)分配的对象使用 shared_ptr
或 weak_ptr
,或者对 shared_ptr
使用 weak_ptr
(唯一)由对象拥有以指示其生命周期结束。
以上是使用 C++14 lambdas 捕获对象的共享指针作为弱指针的实现,如果它已被删除,则给出定义的行为(抛出所述弱指针的副本)。
终身令牌如下所示:
using lifetime_token = std::weak_ptr<void>;
struct has_lifetime {
has_lifetime():token(std::make_shared<char>()) {}
has_lifetime(has_lifetime const&o):has_lifetime() {} // not default
lifetime_token get_lifetime() const {
return token;
}
private:
std::shared_ptr<void> token;
};
从 has_lifetime
继承给你一个 get_lifetime()
成员,只要你这样做就存在(它被你的析构函数销毁,并且不再是 .lock()
d)。
如果您无法修改原始 class 的所有权语义,则此模式更容易遵循。只需 .lock()
对象的 lifetime_token
来确定它是否还活着。