繁体   English   中英

功能对象与状态

[英]Function Objects vs State

我已经使用函数对象来找出传递的对象发生了什么,以及它如何影响对象的状态。 这是测试代码的片段:

#include <iostream>
//#include <boost/function.hpp>
//using boost::function;

#include <functional>
using std::function;
using std::bind;

struct A {
  A() { std::cout << "Creating..." << "\n"; }
  void operator()() { call(); }
  void call() { std::cout << "Executing call..." << "\n"; }
  virtual ~A() { std::cout << "Destroying" << "\n"; }
};

typedef function<void ()> Func;

struct B{
  Func f;
  B(Func ff) : f(ff) {}
  void call() {f();}
};

int main(int argc, char *argv[])
{
  {
    A a;
    B b(a);
    for (int i = 0; i < 5; ++i)
      b.call();
  }
  {
    A a2;
    B b2(bind(&A::call, &a2));
    for (int i = 0; i < 5; ++i)
      b2.call();
  }
  return 0;
}

/** Output **
  Creating...
  Destroying
  Destroying
  Executing call...
  Executing call...
  Executing call...
  Executing call...
  Executing call...
  Destroying
  Destroying
  Creating...
  Executing call...
  Executing call...
  Executing call...
  Executing call...
  Executing call...
  Destroying
 */

当我在操作符()重载的情况下传递对象时,会有多个对析构函数的调用。 并没有创建任何对象! 因此,可以说,我不能依靠对象状态的保真度。 这是否意味着当我传递一个函数对象(带有重载的operator())以进行回调时,我应该假定该对象的状态未保留? 这是预期的行为吗?

另一方面,从另一个类型的对象内部回调绑定的成员函数会产生非常稳定的行为(我不知道使用什么术语) 也就是说,我希望对象状态得以保留; 确实是! 这也是预期的行为吗? IOW,函子通常是如何理解的?

PS:

我还用boost :: function和boost :: bind进行了检查---结果非常相似。 可能需要另一个线程来讨论细微差别。

当我在操作符()重载的情况下传递对象时,会有多个对析构函数的调用。 并没有创建任何对象!

您没有计算使用复制构造函数构造的对象,该构造函数是在您不提供复制构造函数时创建的。

将复制构造函数添加到A ,您将看到对析构函数的调用次数与对构造函数的调用次数相同。

struct A {
  A() { std::cout << "Creating..." << "\n"; }

  // Add this
  A(A const& copy) { std::cout << "Creating..." << "\n"; }

  void operator()() { call(); }
  void call() { std::cout << "Executing call..." << "\n"; }
  virtual ~A() { std::cout << "Destroying" << "\n"; }
};

关于“没有构造函数”:存在对复制构造函数的调用。

尝试更多检测:

struct A {
  A() { std::cout << "Creating..." << "\n"; }
  void operator()() { call(); }
  A(const A&) { std::cout << "Copying" << "\n"; }
  A(A&&) { std::cout << "Moving" << "\n"; } // Assuming C++11
  void call() { std::cout << "Executing call..." << "\n"; }
  virtual ~A() { std::cout << "Destroying" << "\n"; }
};  

关于复制:

  • 您将按值将可调用对象移交给B的构造函数。 它必须被复制。
  • 绑定,如果您输入值,这就是预期的行为。 您要绑定的可呼叫对象可能是临时的。 因此,默认行为是复制。

您可以通过使用引用包装器避免这种情况,如果您知道可调用对象将存活足够长的时间(就像您的代码中那样)。 尝试:

int main(int argc, char *argv[])
{
  {
    A a;
    {
      B b(a);
    }
    std::cout << "-------------\n";
    B(std::ref(a));
    std::cout << "-------------\n";
    B(bind(&A::call, a));
    std::cout << "-------------\n";
    B(bind(&A::call, &a));
    std::cout << "-------------\n";
    B(bind(&A::call, std::ref(a)));
    std::cout << "-------------\n";
  }
  std::cout << "-------------\n";
  return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM