- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个简单的类,它的构造函数如下所示:
Event(std::function<void()> &&f) : m_f(std::move(f)) { }
构造函数可以与 std::bind 一起使用:
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!
PS:我用 C++11 和 14 标记了这个问题,因为使用此处找到的常用 make_unique 函数将 C++11 标志传递给 gcc 时会发生同样的问题 (make_unique and perfect forwarding)
最佳答案
我认为使用 make_unique
时的附加步骤是由于在 Event(std::bind(lambda,thing))
中移动省略 .
Event
的构造函数被称为Event(function<void()> && f)
,所以临时 function<void()>
必须创建。这个临时文件是用 std::bind
的返回值初始化的表达。
用于从 std::bind
的返回类型执行此转换的构造函数至 std::function<void()>
按值获取参数:
template<class F> function(F f); // ctor
这意味着我们必须移动 std::bind
的返回值到这个参数 f
function<void()>
的构造函数.但是该移动符合移动省略的条件。
当我们通过 make_unique
传递那个临时值时,它已经绑定(bind)到一个引用,移动省略可能不再适用。如果我们因此抑制移动省略:
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";
(我们可以使用 std::move
作为 suppress_elision
的实现。)
我们可以观察到相同的移动次数:Live example
解释整套操作:
对于 new Event(std::bind(lambda,thing))
:
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 (+)
(*)可以省略
(+) 但没有,可能是因为内部函数对象在堆上,并且只移动了一个指针。 Verify by replacing m_f(std::move(f))
with m_f()
.
对于 make_unique<Event>(std::bind(lambda,thing))
:
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 (+)
关于c++ - 为什么 make_unique 有一个可以将 std::bind 作为参数的构造函数的额外移动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27952709/
struct Foo{}; std::make_unique 之间有什么区别?和 std::make_unique> ? 最佳答案 std::make_unique创建一个 Foo具有动态存储持续时间
我正在实现循环数组数据结构,其代码如下所示: struct CircularArrayException : public std::exception { std::string msg;
全部, 我正在使用 C++14 并正在制作一个或多或少的标准单例。我正在使用最新的 Visual Studio 2017。此代码有效: #include class A { public: st
我想知道使用智能指针(如下面代码中的 Box3 )声明 Box 是否比(对我来说更经典)声明有任何优势调用构造函数(如下面代码中的 Box2)或者这两种构造之间的差异本质上是主观偏好的问题。 #inc
我在构建时不断收到以下错误, use of undeclared identifier 'make_unique' m_planet = make_unique(); 我的头文件给出了错误, #inc
我需要一个类作为延迟工厂工作,保存参数以创建另一个类并稍后及时调用 make_unique。到目前为止,我没有任何运气让可变模板版本工作。任何帮助将不胜感激(下面的最小非工作版本)。 template
https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique写道 std::make_unique 可以实现为 template st
我正在尝试为 std::unique_ptr 创建和使用 make_unique,就像 std::make_shared 存在于 std::shared_ptr described here .赫伯萨
作为 this 的后续行动发布后我想知道它的 make_unique 实现如何与分配函数临时缓冲区数组一起使用,例如以下代码。 f() { auto buf = new int[n]; // te
澄清一下,使用 make_unique 仅在表达式中有多个分配时才增加异常安全性,而不仅仅是一个,对吗?例如 void f(T*); f(new T); 是完全异常安全的(就分配和东西而言),而 vo
为什么没有std::make_unique标准 C++11 库中的函数模板?我发现 std::unique_ptr p(new SomeUserDefinedType(1, 2, 3)); 有点冗长。
考虑以下基类和派生类。 class base { public: int i{9}; virtual void func() { cout ptr{new d
在下面的代码中,有什么方法可以将参数传递给 demo使用时的构造函数 std::make_unique()分配一个 demo[]大批? class demo{ public: int info
有没有办法使用 make_unique 并将函数的输出作为参数传递? auto loadedSurface1 = std::unique_ptr(IMG_Load(path.c_str())); au
这个问题在这里已经有了答案: Template deduction for function based on its return type? (6 个答案) 关闭 4 年前。 例如我得到了这段代
make_unique 如果设计成这样,会不会更有用: template unique_ptr make_unique( ArgT ...args ) { return unique_ptr(
我遇到了 make_unique 的问题,我对此一头雾水。 _replace_find = unique_ptr(new Fl_Input{ 80, 10, 210, 25, "Find:" });
我无法找到任何关于如果将空指针传递给 std::make_unique 会发生什么的文档。 是否抛出异常? 最佳答案 std::make_unique将传递给匹配目标构造函数的所有参数转发。因此,如果
这个问题在这里已经有了答案: using c++ aggregate initialization in std::make_shared (3 个答案) 关闭 5 年前。 刚开始学习智能指针 st
我有一个 Factory 的小例子设计模式,我对这部分很感兴趣: std::make_unique(*this) ...尤其是*this . 这是否意味着 clone()方法返回 std::uniqu
我是一名优秀的程序员,十分优秀!