14

我有这个代码:

#include <iostream>
#include <functional>

struct Foo
{
        int get(int n) { return 5+n; }
};

int main()
{
        Foo foo;
        auto L = std::bind(&Foo::get, &foo, 3);

        std::cout << L() << std::endl;

        return 0;
}

似乎是这样的:

auto L = std::bind(&Foo::get, &foo, 3);

相当于:

auto L = std::bind(&Foo::get, foo, 3);

为什么?

4

2 回答 2

23

std::bind()按值接受其参数。这意味着在第一种情况下,您按值传递指针,从而产生指针的副本。在第二种情况下,您foo按值传递类型对象,从而生成类型对象的副本Foo

因此,在第二种情况下,表达式的评估会导致在原始 object的副本上调用L()成员函数,这可能是也可能不是您想要的。get()foo

这个例子说明了区别(忘记违反三规则/五规则,这只是为了说明目的):

#include <iostream>
#include <functional>

struct Foo
{
    int _x;

    Foo(int x) : _x(x) { }

    Foo(Foo const& f) : _x(f._x)
    {
        std::cout << "Foo(Foo const&)" << std::endl;
    }

    int get(int n) { return _x + n; }
};

int main()
{
   Foo foo1(42);

   std::cout << "=== FIRST CALL ===" << std::endl;
   auto L1 = std::bind(&Foo::get, foo1, 3);
   foo1._x = 1729;
   std::cout << L1() << std::endl; // Prints 45

   Foo foo2(42);

   std::cout << "=== SECOND CALL ===" << std::endl;
   auto L2 = std::bind(&Foo::get, &foo2, 3);
   foo2._x = 1729;
   std::cout << L2() << std::endl; // Prints 1732
}

活生生的例子

如果出于任何原因不想使用指针形式,则可以使用std::ref()来防止创建参数的副本:

auto L = std::bind(&Foo::get, std::ref(foo), 3);
于 2013-04-15T13:21:47.783 回答
4

它们是不相同的。通用函数 binderstd::bind 复制它的参数。在 的情况下std::bind(&Foo::get,&foo,3)指针被复制,但是当您调用绑定对象时,它仍然适用于原始foo对象。在std::bind(&Foo::get,foo,3)对象foo被复制时,后面的调用适用于绑定的副本,而不是原始对象。

您可以使用访问对象内部状态的成员函数对此进行测试,以两种方式绑定对象,更改原始对象并查看结果有何不同。

于 2013-04-15T13:21:08.147 回答