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 (+)