我知道有5个常规类别,其中将C ++ 03编译器重新编译为C ++ 11可能会导致性能的无限提高,而这实际上与实现质量无关。这些都是移动语义的变体。
std::vector
重新分配
struct bar{
std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03
每次时间foo
的缓冲器被在C ++ 03重新分配它复制每个vector
中bar
。
在C ++ 11中,它移动bar::data
s,而s基本上是免费的。
在这种情况下,这取决于std
container 内的优化vector
。在下面的每种情况下,使用std
容器仅仅是因为它们是C ++对象,move
在升级编译器时,它们在C ++ 11中具有“自动” 高效的语义。包含std
容器的不阻止它的对象也继承自动改进的move
构造函数。
NRVO故障
当NRVO(命名为返回值优化)失败时,在C ++ 03中它回退到副本上,而在C ++ 11中它回退到移动上。NRVO的失败很容易:
std::vector<int> foo(int count){
std::vector<int> v; // oops
if (count<=0) return std::vector<int>();
v.reserve(count);
for(int i=0;i<count;++i)
v.push_back(i);
return v;
}
甚至:
std::vector<int> foo(bool which) {
std::vector<int> a, b;
// do work, filling a and b, using the other for calculations
if (which)
return a;
else
return b;
}
我们有三个值-返回值和函数内的两个不同值。Elision允许将函数内的值与返回值“合并”,但不能相互合并。如果没有合并,它们都不能与返回值合并。
基本的问题是NRVO省略是脆弱的,并且不在return
站点附近进行更改的代码会突然在该位置大幅降低性能,而不会发出诊断信息。在大多数NRVO失败的情况下,C ++ 11的结尾为move
,而C ++ 03的结尾为一个副本。
返回函数参数
此处的省略也是不可能的:
std::set<int> func(std::set<int> in){
return in;
}
在C ++ 11中,这很便宜:在C ++ 03中,无法避免复制。返回值不能忽略函数的参数,因为参数的寿命和位置以及返回值由调用代码管理。
但是,C ++ 11可以从一个迁移到另一个。(在一个不那么玩具的示例中,可以对进行某些操作set
)。
push_back
要么 insert
最终省略到容器中不会发生:但是C ++ 11重载了右值移动插入运算符,从而保存了副本。
struct whatever {
std::string data;
int count;
whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );
在C ++ 03中,将whatever
创建一个临时文件,然后将其复制到vector中v
。std::string
分配了2个缓冲区,每个缓冲区具有相同的数据,而其中一个被丢弃。
在C ++ 11中,将whatever
创建一个临时目录。whatever&&
push_back
然后move
,将重载临时添加到向量中v
。std::string
分配了一个缓冲区,并将其移入向量。空将std::string
被丢弃。
分配
从@ Jarod42的答案中被盗。
分配不能发生省略,但可以移动。
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
这里some_function
返回一个候选对象,但由于它不用于直接构造对象,因此不能被忽略。在C ++ 03中,以上结果导致临时内容被复制到中some_value
。在C ++ 11中,它已移入some_value
,基本上是免费的。
为了充分发挥上述作用,您需要一个可以为您合成move构造函数和赋值的编译器。
MSVC 2013在std
容器中实现move构造函数,但不会在您的类型上合成move构造函数。
因此,包含std::vector
s和类似内容的类型在MSVC2013中不会得到这种改进,但是会在MSVC2015中开始得到它们。
clang和gcc早就实现了隐式move构造函数。如果您通过,英特尔2013编译器将支持隐式生成move构造函数-Qoption,cpp,--gen_move_operations
(默认情况下,为了与MSVC2013交叉兼容,它们不会这样做)。