C++ std move中无副本的赋值
我有一个返回映射的util函数C++ std move中无副本的赋值,c++,c++11,move,rvo,nrvo,C++,C++11,Move,Rvo,Nrvo,我有一个返回映射的util函数 std::map getFooMap() { std::map foo; // ... populate the map return foo; } 在调用方,我想将映射分配给某个对象的数据字段。我可以做到: dest.data = getFooMap() 这会比下面的更快吗 auto temp = getFooMap(); dest.data = std::move(temp); 我想这应该是因为我避免了一个额外的副本 我想这应该是因为我避免了
std::map getFooMap() {
std::map foo;
// ... populate the map
return foo;
}
在调用方,我想将映射分配给某个对象的数据字段。我可以做到:
dest.data = getFooMap()
这会比下面的更快吗
auto temp = getFooMap();
dest.data = std::move(temp);
我想这应该是因为我避免了一个额外的副本
我想这应该是因为我避免了一个额外的副本
只要“std::map
”是可移动的,您就可能只会避免一次额外的移动,优化器也可能会避免
性能差异可能可以忽略或不存在,但dest.data=getFooMap()
更简单,而且可能不会更慢
正如在一篇评论中指出的,直接初始化dest.data
而不是在构建之后分配它会更快。这可以通过在成员初始化器中调用getFooMap
来实现
我想这应该是因为我避免了一个额外的副本
只要“std::map
”是可移动的,您就可能只会避免一次额外的移动,优化器也可能会避免
性能差异可能可以忽略或不存在,但dest.data=getFooMap()
更简单,而且可能不会更慢
正如在一篇评论中指出的,直接初始化
dest.data
而不是在构建之后分配它会更快。这可以通过在成员初始化器中调用getFooMap
来实现。从美学角度来看,它必须是第一个变体。您必须对语言标准和编译器作者有一定的信心,才能不需要像临时文件这样愚蠢的工件来促进优化
让我们检查一下情况是否确实如此。首先,请允许我稍微抽象一下您的示例,并将map
替换为类foo
,而不定义其各种方法;假设没有什么会引发任何异常:
#include <utility>
// Originally this was an std::map, replaced with
// an "opaque" class to shorten the output and
// prevent inlining and conflation of
// std-map-related code with the rest of the code
struct foo {
foo() noexcept;
foo(const foo&) noexcept;
foo(foo&&) noexcept;
foo& operator=(foo&&) noexcept;
foo& operator=(const foo&) noexcept;
~foo() noexcept;
};
struct dest_t { foo data; };
foo get_foo() noexcept;
void do_stuff_with(const dest_t& dest) noexcept;
void move_from_intermediate() noexcept {
dest_t dest;
auto temp = get_foo();
dest.data = std::move(temp);
do_stuff_with(dest);
}
void straight_assignment() noexcept {
dest_t dest;
dest.data = get_foo();
do_stuff_with(dest);
}
#包括
//最初这是一个std::map,替换为
//一个“不透明”类,用于缩短输出和
//防止内联和合并
//std映射相关代码与其余代码
结构foo{
foo()不例外;
foo(const foo&)无例外;
foo(foo&&)无例外;
foo&运算符=(foo&&)无例外;
foo&运算符=(const foo&)noexcept;
~foo()不例外;
};
struct dest{foo data;};
foo get_foo()无例外;
void do_stuff_(const dest&dest)无例外;
void move_from_mediate()noexcept{
目的地;
auto temp=get_foo();
目的地数据=标准::移动(温度);
与(目的地)一起工作;
}
void stright_赋值()无例外{
目的地;
dest.data=get_foo();
与(目的地)一起工作;
}
现在,如果我们看到GCC(trunk)为这两个函数生成相同的汇编代码。这包括:
- 1建筑
- 2破坏
- 1移动作业
- 1调用
get\u foo()
- 1调用
do\u stuff\u with()
在这两种情况下。clang(trunk)也将生成相同的代码,甚至可以进行轻微的重新排序-但与GCC的代码并不完全相同。从美学角度来看,它必须是第一个变体。您必须对语言标准和编译器作者有一定的信心,才能不需要像临时文件这样愚蠢的工件来促进优化 让我们检查一下情况是否确实如此。首先,请允许我稍微抽象一下您的示例,并将
map
替换为类foo
,而不定义其各种方法;假设没有什么会引发任何异常:
#include <utility>
// Originally this was an std::map, replaced with
// an "opaque" class to shorten the output and
// prevent inlining and conflation of
// std-map-related code with the rest of the code
struct foo {
foo() noexcept;
foo(const foo&) noexcept;
foo(foo&&) noexcept;
foo& operator=(foo&&) noexcept;
foo& operator=(const foo&) noexcept;
~foo() noexcept;
};
struct dest_t { foo data; };
foo get_foo() noexcept;
void do_stuff_with(const dest_t& dest) noexcept;
void move_from_intermediate() noexcept {
dest_t dest;
auto temp = get_foo();
dest.data = std::move(temp);
do_stuff_with(dest);
}
void straight_assignment() noexcept {
dest_t dest;
dest.data = get_foo();
do_stuff_with(dest);
}
#包括
//最初这是一个std::map,替换为
//一个“不透明”类,用于缩短输出和
//防止内联和合并
//std映射相关代码与其余代码
结构foo{
foo()不例外;
foo(const foo&)无例外;
foo(foo&&)无例外;
foo&运算符=(foo&&)无例外;
foo&运算符=(const foo&)noexcept;
~foo()不例外;
};
struct dest{foo data;};
foo get_foo()无例外;
void do_stuff_(const dest&dest)无例外;
void move_from_mediate()noexcept{
目的地;
auto temp=get_foo();
目的地数据=标准::移动(温度);
与(目的地)一起工作;
}
void stright_赋值()无例外{
目的地;
dest.data=get_foo();
与(目的地)一起工作;
}
现在,如果我们看到GCC(trunk)为这两个函数生成相同的汇编代码。这包括:
- 1建筑
- 2破坏
- 1移动作业
- 1调用
get\u foo()
- 1调用
do\u stuff\u with()
在这两种情况下。clang(trunk)也将生成相同的代码,甚至可以进行轻微的重新排序,但与GCC的代码并不完全相同。好的编译器将优化两个调用,使其执行几乎相同的操作,但如果不是这样,则首选第一个。为什么要立即将返回的变量命名为
std::move
呢?是否检查了程序集?FWIW,我听说std::move
禁止,所以对于一个好的编译器,我希望move-less选项比std::move
更快,或者至少与std::move
的选项一样快。最好是使用getFooMap()
调用来构造dest.data
,这通常意味着在构造dest
时进行调用。这对您来说可能吗?好的编译器会优化两个调用,使其几乎做相同的事情,尽管如果不是这样,则首选第一个。为什么要立即将返回的变量命名为std::move
呢?是否检查了程序集?FWIW,我听说std::move
禁止,所以对于一个好的编译器,我希望move-less选项更快,或者至少与std::move
的选项一样快。最好是使用getFooMap()
调用来构造dest.data
,这通常意味着在