现代C ++能让你免费获得性能吗? [英] Can modern C++ get you performance for free?

查看:107
本文介绍了现代C ++能让你免费获得性能吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时声称C ++ 11/14可以提高性能,即使只是编译C ++ 98代码。调整通常是沿着移动语义线,因为在某些情况下,右值构造函数是自动生成的,或者现在是STL的一部分。现在我想知道这些情况是否以前实际上已经由RVO或类似的编译器优化处理。

It is sometimes claimed that C++11/14 can get you a performance boost even when merely compiling C++98 code. The justification is usually along the lines of move semantics, as in some cases the rvalue constructors are automatically generated or now part of the STL. Now I'm wondering whether these cases were previously actually already handled by RVO or similar compiler optimizations.

我的问题是,如果你能给我一个C ++ 98代码的实际例子,没有修改,使用支持新语言的编译器运行得更快特征。我明白,一个标准的合格编译器不需要做复制精度,只是因为移动语义可能带来速度,但我想看到一个较少病理的情况下,如果你愿意。

My question then is if you could give me an actual example of a piece of C++98 code that, without modification, runs faster using a compiler supporting the new language features. I do understand that a standard conforming compiler is not required to do the copy elision and just by that reason move semantics might bring about speed, but I'd like to see a less pathological case, if you will.

编辑:为了清楚,我不是问新的编译器是否比旧的编译器更快,而是如果有代码,通过添加-std = c ++ 14到我的编译器标志运行速度更快(避免复制,但如果你能想出除了移动语义之外的任何东西,我也会感兴趣)

Just to be clear, I am not asking whether new compilers are faster than old compilers, but rather if there is code whereby adding -std=c++14 to my compiler flags it would run faster (avoid copies, but if you can come up with anything else besides move semantics, I'd be interested, too)

推荐答案

p>我知道5个一般类别,其中重新编译C ++ 03编译器作为C ++ 11可以导致无关的性能增加,实际上与实现的质量无关。这些都是移动语义的变体。

I am aware of 5 general categories where recompiling a C++03 compiler as C++11 can cause unbounded performance increases that are practically unrelated to quality of implementation. These are all variations of move semantics.

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中重新分配它在 bar中复制每个向量 >。

every time the foo's buffer is reallocated in C++03 it copied every vector in bar.

在C ++ 11中,它会移动 bar :: data s,基本上是免费的。

In C++11 it instead moves the bar::datas, which is basically free.

在这种情况下,这依赖于 std 容器中的优化。在下面的每种情况下,使用 std 容器只是因为它们是在C中具有高效 move 语义的C ++对象++ 11自动,当你升级你的编译器。不阻塞它的包含 std 容器的对象也继承自动改进的 move 构造函数。

In this case, this relies on optimizations inside the std container vector. In every case below, the use of std containers is just because they are C++ objects that have efficient move semantics in C++11 "automatically" when you upgrade your compiler. Objects that don't block it that contain a std container also inherit the automatic improved move constructors.

当NRVO(命名返回值优化)失败时,在C ++ 03中它会返回copy C ++ 11它回到移动。 NRVO的失败很容易:

When NRVO (named return value optimization) fails, in C++03 it falls back on copy, on C++11 it falls back on move. Failures of NRVO are easy:

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允许函数中的值与返回值合并,但不能彼此合并。

We have three values -- the return value, and two different values within the function. Elision allows the values within the function to be 'merged' with the return value, but not with each other. They both cannot be merged with the return value without merging with each other.

基本问题是,NRVO elision很脆弱,代码的变化不在 return 网站可以突然大幅降低性能,没有诊断。在大多数NRVO失败的情况下,C ++ 11最终以 move 结束,而C ++ 03最终以副本结束。

The basic issue is that NRVO elision is fragile, and code with changes not near the return site can suddenly have massive performance reductions at that spot with no diagnostic emitted. In most NRVO failure cases C++11 ends up with a move, while C++03 ends up with a copy.

Elision在这里也不可能:

Elision is also impossible here:

std::set<int> func(std::set<int> in){
  return in;
}

在C ++ 11中这是很便宜的:在C ++ 03中有没有办法避免复制。

in C++11 this is cheap: in C++03 there is no way to avoid the copy. Arguments to functions cannot be elided with the return value, because the lifetime and location of the parameter and return value is managed by the calling code.

但是,C ++ 11的参数和返回值的生命周期和位置是由调用代码管理的。可以从一个移动到另一个。 (在一个较少的玩具示例中,可能会对 set 执行一些操作。)

However, C++11 can move from one to the other. (In a less toy example, something might be done to the set).

11重载rvalue move插入运算符,它保存副本。

Finally elision into containers does not happen: but C++11 overloads rvalue move insert operators, which saves copies.

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中临时无论 ,然后将其复制到向量 v 中。 2 std :: string 缓冲区被分配,每个都有相同的数据,一个被丢弃。

in C++03 a temporary whatever is created, then it is copied into the vector v. 2 std::string buffers are allocated, each with identical data, and one is discarded.

+11创建了一个临时 whatever whatever&& push_back 重载,然后 move 临时插入向量 v 。分配一个 std :: string 缓冲区,并将其移动到向量中。将舍弃一个空的 std :: string

In C++11 a temporary whatever is created. The whatever&& push_back overload then moves that temporary into the vector v. One std::string buffer is allocated, and moved into the vector. An empty std::string is discarded.

从@ Jarod42的回答中偷走了

Stolen from @Jarod42's answer below.

Elision不能在分配时发生,但可以从移动。

Elision cannot occur with assignment, but move-from can.

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 中,基本上是免费的。

here some_function returns a candidate to elide from, but because it is not used to construct an object directly, it cannot be elided. In C++03, the above results in the contents of the temporary being copied into some_value. In C++11, it is moved into some_value, which basically is free.

对于上述的全部效果,你需要一个合成移动构造函数和赋值给你的编译器。

For the full effect of the above, you need a compiler that synthesizes move constructors and assignment for you.

MSVC 2013在 std 容器,但不会在您的类型上合成move构造函数。

MSVC 2013 implements move constructors in std containers, but does not synthesize move constructors on your types.

:vector s和类似的在MSVC2013没有得到这样的改进,但将开始在MSVC2015中获得它们。

So types containing std::vectors and similar do not get such improvements in MSVC2013, but will start getting them in MSVC2015.

clang和gcc早已实现隐式移动构造函数。如果你通过 -Qoption,cpp, - gen_move_operations (他们不会在默认情况下这样做),英特尔2013编译器将支持隐式生成移动构造函数,兼容MSVC2013)。

clang and gcc have long since implemented implicit move constructors. Intel's 2013 compiler will support implicit generation of move constructors if you pass -Qoption,cpp,--gen_move_operations (they don't do it by default in an effort to be cross-compatible with MSVC2013).

这篇关于现代C ++能让你免费获得性能吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆