C++ 为什么make_unique会有一个可以将std::bind作为参数的构造函数的额外移动?

C++ 为什么make_unique会有一个可以将std::bind作为参数的构造函数的额外移动?,c++,c++11,c++14,C++,C++11,C++14,我有一个平凡的类,它的构造函数如下所示: Event(std::function<void()> &&f) : m_f(std::move(f)) { } PS:我用C++11和14标记了这个问题,因为将C++11标志传递给gcc时,使用此处常用的make_unique函数()会出现同样的问题。我认为使用make_unique时的额外移动是由于事件(std::bind(lambda,thing))中的移动省略造成的 调用的事件的构造函数是事件(函数&f),因此必须创

我有一个平凡的类,它的构造函数如下所示:

Event(std::function<void()> &&f) : m_f(std::move(f)) { }

PS:我用C++11和14标记了这个问题,因为将C++11标志传递给gcc时,使用此处常用的make_unique函数()会出现同样的问题。

我认为使用
make_unique时的额外移动是由于
事件(std::bind(lambda,thing))
中的移动省略造成的

调用的
事件
的构造函数是
事件(函数&f)
,因此必须创建一个临时的
函数
。使用
std::bind
表达式的返回值初始化此临时变量

用于执行从返回类型
std::bind
std::function
的转换的构造函数按值获取参数:

(我们可以使用
std::move
作为
suppress\u-elision
的实现)

我们可以观察到相同数量的移动:


解释整套操作:

对于
新事件(std::bind(lambda,thing))


有可能
对象
嵌入在
std::function
中,在这种情况下,
m_f(std::move(f))
也会移动
对象。与
sizeof(std::function)
相比,
sizeof(Thing)
有多大?它应该嵌入到函数中;bind按值获取“thing”。另外,sizeof(std::function)或Event中的f是32,sizeof(Thing)是4,我想@dyp已经知道了-将
bind
对象转换为
std::function
发生在
make_unique
内部,因此,不能省略
函数
构造函数参数的移动初始化,因为它在非
make_unique
情况下可以省略。
移动(std::bind(…)
?我相当确定
std::bind
的返回值已经尽可能地正确;)哦,没关系-你用演员阵容来压制省略。我是个白痴。很棒的解释和事件顺序图。。。你为什么认为它不正确?那么我应该等待另一个答案吗?@Pris我忘了您需要从
std::function
的by-value-ctor参数移动到
std::function
对象本身(或它在堆上管理的部分)。这意味着最后一步并没有像@MooingDuck所说的那样真正发生。
Thing thing;
std::unique_ptr<Event> ev(new Event(std::bind(some_func,thing)));
std::unique_ptr<Event> ev = make_unique<Event>(std::bind(some_func,thing));
#include <iostream>
#include <memory>
#include <functional>
using namespace std;

class Thing
{
public:
    Thing() : x(0)
    {

    }

    Thing(Thing const &other)
    {
        this->x = other.x;
        std::cout << "Copy constructed Thing!\n";
    }

    Thing(Thing &&other)
    {
        this->x = other.x;
        std::cout << "Move constructed Thing!\n";
    }

    Thing & operator = (Thing const &other)
    {
        this->x = other.x;
        std::cout << "Copied Thing!\n";
        return (*this);
    }

    Thing & operator = (Thing && other)
    {
        this->x = other.x;
        std::cout << "Moved Thing!\n";
        return (*this);
    }

    int x;
};

class Event
{
public:
    Event() { }
    Event(function<void()> && f) : m_f(std::move(f)) { }
    void SetF(function<void()> && f) { m_f = std::move(f); }

private:
    function<void()> m_f;
};

int main() {

    auto lambda = [](Thing &thing) { std::cout << thing.x << "\n"; };

    Thing thing;
    std::cout << "without unique_ptr: \n";
    Event ev(std::bind(lambda,thing));
    std::cout << "\n";

    std::cout << "with unique_ptr, no make_unique\n";
    unique_ptr<Event> ev_p(new Event(std::bind(lambda,thing)));
    std::cout << "\n";

    std::cout << "with make_unique: \n";
    auto ev_ptr = make_unique<Event>(std::bind(lambda,thing));
    std::cout << "\n";

    std::cout << "with SetF: \n";
    ev_ptr.reset(nullptr);
    ev_ptr = make_unique<Event>();
    ev_ptr->SetF(std::bind(lambda,thing));
    std::cout << "\n";

    return 0;
}
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
or
clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

without unique_ptr: 
Copy constructed Thing!
Move constructed Thing!

with unique_ptr, no make_unique
Copy constructed Thing!
Move constructed Thing!

with make_unique: 
Copy constructed Thing!
Move constructed Thing!
Move constructed Thing!

with SetF: 
Copy constructed Thing!
Move constructed Thing!
template<class F> function(F f); // ctor
std::cout << "with unique_ptr, no make_unique\n";
unique_ptr<Event> ev_p(new Event(suppress_elision(std::bind(lambda,thing))));
std::cout << "\n";

std::cout << "with make_unique: \n";
auto ev_ptr = make_unique<Event>(suppress_elision(std::bind(lambda,thing)));
std::cout << "\n";
operation | behaviour ------------------------------------------------------+---------- `thing` variable -> `bind` temporary | copies `bind` temporary -> `function` ctor param | moves (*) `function` ctor param -> `function` object (temp) | moves `function` temporary -> `Event` ctor ref param | - `Event` ctor ref param -> `function` data member | *can* move (+) operation | behaviour --------------------------------------------------------+---------- `thing` variable -> `bind` temporary | copies `bind` temporary -> `make_unique` ref param | - `make_unique` ref param -> `function` ctor param | moves `function` ctor param -> `function` object (temp) | moves `function` temporary -> `Event` ctor ref param | - `Event` ctor ref param -> `function` data member | *can* move (+)