【问题标题】:Why is the copy ctor invoked twice when using std::bind?为什么在使用 std::bind 时会调用两次复制 ctor?
【发布时间】:2018-11-06 00:46:35
【问题描述】:

我正在使用std::functionstd::bind 来了解如何复制参数以及是否可以保存一些复制操作。

我了解当使用std::bind 时,参数是按值而不是引用传递的(除非指定了std::ref)。但是,当我运行以下 sn-p 时,复制构造函数被调用了两次。谁能解释一下原因?

struct token
{
    static int i;
    int code;

    token()
        : code(i++)
    {
        cout << __FUNCTION__ << ": " << code << endl;
    }
    virtual ~token()
    {
        cout << __FUNCTION__ << endl;
    }

    token (token const & other)
        : code (other.code)
    {
        cout << "copy ctor: " << code << endl;
    }

    // update -- adding a move ctor
    token (token const && other)
        : code (std::move(other.code))
    {
        cout << "move ctor: " << code << endl;
    }
    // update -- end

    void boo() const
    {
            cout << __FUNCTION__ << ": " << code << endl;
    }


};

void call_boo(token const & t)
{
    t.boo();
}


int main()
{
    token t2;

    cout << "default" << endl;
    std::function< void () >(std::bind(&call_boo, t2));

    cout << "ref" << endl;
    std::function< void () >(std::bind(&call_boo, std::ref(t2)));

    cout << "move" << endl;
    std::function< void () >(std::bind(&call_boo, std::move(t2)));


    cout << "end" << endl;
    return 0;
}

运行时,会产生以下输出:

token: 1
default
// Without move ctor
// copy ctor: 1 // Makes sense. This is the passing by value.
// copy ctor: 1 // Why does this happen?
// With move ctor    
copy ctor: 1
move ctor: 1
~token
~token
ref // No copies. Once again, makes sense.
move
// Without move ctor
// copy ctor: 1
// copy ctor: 1
// With move ctor
move ctor: 1
move ctor: 1
~token
~token
end
~token

【问题讨论】:

  • 您是否考虑过using the gdb debugger 并设置断点来了解何时调用构造函数?
  • 我猜它首先被复制到活页夹函子中,然后后者被移动到 std::function 对象中。但是由于您的 token 没有专用的移动构造函数,因此使用了复制构造函数。基本上,一切都如预期的那样。
  • 现代有效 C++,第 34 条:优先使用 lambdas 而非 std::bind。
  • 说真的,您自己的问题可以通过在调试器中放置一个断点并查看调用堆栈来回答。

标签: c++ std-function stdbind


【解决方案1】:

std::function 的这个构造函数的参数总是被复制的,所以在 std::function 中创建了一个绑定对象的副本(它本身有一个令牌对象的副本)。

http://en.cppreference.com/w/cpp/utility/functional/function/function

template< class F > 
function( F f );

5) 用 f 的副本初始化目标。如果 f 是指向函数的空指针或指向成员的空指针,则 *this 在调用后将为空。此构造函数不参与重载决议,除非 f 对于参数类型 Args... 和返回类型 R 是 Callable。(C++14 起)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-17
相关资源
最近更新 更多