【问题标题】:Bind a valid class object pointer to boost::function<>fn. What may happen if invoking the `fn` after the object has been destoryed?将有效的类对象指针绑定到 boost::function<>fn。如果在对象被销毁后调用 `fn` 会发生什么?
【发布时间】:2020-12-13 08:39:34
【问题描述】:

绑定一个类成员函数和一个有效的类对象指针到 boost::functionfn。如果在指针指向的对象被销毁之后调用fn 会发生什么? 是否有一些我应该注意的潜在问题? Domo 代码快照:

 class CTest
 {
    public:
         int demo(void){}
 };

 
 int main()
 {
    boost::function<int(void)> fn;
    {
        CTest ins;
        fn = boost::bind(&CTest::demo, &ins); 
    }
    fn();
}

已编辑(https://godbolt.org/z/r8EK1G)

引用自j6t的评论

一种方法是通过值传递对象,而不是指向 目的。然后在调用期间将使用对象的副本 fn()。 我认为仍然存在对象“tes”超出范围的问题。因此,传递值不是一个好方法。 :

 #include<functional>
 #include<iostream>

 class CTest
 {
    public:
         int demo(void){std::cout << "do better" << std::endl;return 0;}
 };

template <class T=CTest>
std::function<int(void)>  bindWarp(T obj, int (T::*mem_func)(void))
{
    return std::bind(mem_func, obj);
}

 int main()
 {
    std::function<int(void)> fn;
    {
        CTest tes;
        fn = bindWarp(tes, &CTest::demo);  
    }
    fn();  //I think there is still a problem that the object 'tes' is out of scope.So passing value is not a good method.
}

【问题讨论】:

  • 您的程序有未定义的行为。任何事情都有可能发生。
  • @j6t 你的意思是我必须保证调用std::function对象时指针(指向一个对象)仍然有效?
  • 是的,当然。一种方法是按值传递对象,而不是指向对象的指针。然后将在调用fn() 期间使用对象的副本
  • @j6t“按值传递对象”?不是参考吗?你的意思是这个()?我认为这段代码 sn-p 有同样的问题。 godbolt.org/z/r8EK1G。我将此代码 sn-p 更新到帖子中。
  • 这与你可以用更简单的方式得到的奇怪行为相同,而无需使用 std::function。见this example;但正如其他人所说,您处于 UB 领域。在这种情况下,它“有效”是因为demo 函数不访问this,(至少,对于许多编译器来说,这可能是原因)。但这只是“任何事情都可能发生”,即使它有效

标签: c++ c++11 boost boost-function


【解决方案1】:

您需要确保目标对象的生命周期超过函数对象的生命周期。这更容易用 lambda 函数而不是 bind 以一种明显的方式表达。 lambda 可以明确地“按值”捕获对象:

std::function<int(void)> fn;
{
    CTest tes;
    fn = [tes] { tes.demo(); };
}
fn();

使用 std::bind,您还可以通过以下方式明确表达这一点,并避免复制:

fn = std::bind(&CTest::demo, std::move(tes));

您也可以通过按值而不是按引用来绑定,但我更喜欢上面的两个构造,因为它们的意图非常明确(复制对象或转移所有权)。

如果您想避免所有权的复制或转移,您可以使用带有 lambda 的共享指针。您甚至可以在 lambda 中使用 weak_ptr,这样对象就不会为它保持活动状态。

另请参阅有关现代 C++ 中绑定和 lambda 的详细信息的非常有用的讨论:https://stackoverflow.com/a/17545183/21974

【讨论】:

  • 对象(std::move(tes)传递)何时被销毁?是否与fn 具有相同的生命周期?
  • 传递的对象驻留在fn 中,并随它一起被销毁。来自 std::bind 的文档: std::bind 的返回类型包含 […] 和每个 args 一个对象…,类型为 std::decay::type。
猜你喜欢
  • 1970-01-01
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 2016-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多