函数对象与状态
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()重载的对象时,有一些对析构函数的多次调用;并且没有创建任何对象!所以,我不能依赖,也就是说,对象状态的保真度。这是否意味着当我为回调传递一个函数对象(带有重载的 operator())时,我应该假设对象的状态没有被保留? 这是预期的行为吗?
另一方面,从另一种类型的对象内部回调绑定成员函数会产生非常稳定的行为(我不知道该用什么术语) ;也就是说,我希望保留对象状态;确实如此! 这也是有意为之的行为吗? IOW,这就是函子的普遍理解方式吗?
PS:
我也用boost::function和boost::bind查了一下——结果很相似。可能需要另一个线程来讨论细微差别。
When I pass the object with operator () overloaded, there is some multiple calls to destructors; and no objects are being created!
您没有计算使用复制构造函数构造的对象,它是在您未提供任何对象时由编译器创建的。
向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"; }
};
关于"no constructors": 有对复制构造函数的调用。
尝试更多检测:
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;
}
我已经使用函数对象来了解传递的对象发生了什么,以及它如何影响对象的状态。这是测试代码的片段:
#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()重载的对象时,有一些对析构函数的多次调用;并且没有创建任何对象!所以,我不能依赖,也就是说,对象状态的保真度。这是否意味着当我为回调传递一个函数对象(带有重载的 operator())时,我应该假设对象的状态没有被保留? 这是预期的行为吗?
另一方面,从另一种类型的对象内部回调绑定成员函数会产生非常稳定的行为(我不知道该用什么术语) ;也就是说,我希望保留对象状态;确实如此! 这也是有意为之的行为吗? IOW,这就是函子的普遍理解方式吗?
PS:
我也用boost::function和boost::bind查了一下——结果很相似。可能需要另一个线程来讨论细微差别。
When I pass the object with operator () overloaded, there is some multiple calls to destructors; and no objects are being created!
您没有计算使用复制构造函数构造的对象,它是在您未提供任何对象时由编译器创建的。
向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"; }
};
关于"no constructors": 有对复制构造函数的调用。
尝试更多检测:
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;
}