C++ 可以使用C++;11';s';自动';提高绩效?
我可以理解为什么C++11中的C++ 可以使用C++;11';s';自动';提高绩效?,c++,performance,c++11,auto,C++,Performance,C++11,Auto,我可以理解为什么C++11中的auto类型提高了正确性和可维护性。我已经读到它也可以提高性能(由Herb Sutter编写),但是我错过了一个很好的解释 auto如何提高性能 有人能举个例子吗 因为auto推导初始化表达式的类型,所以不涉及类型转换。与模板算法相结合,这意味着您可以得到比自己创建类型更直接的计算——尤其是在处理无法命名其类型的表达式时 一个典型的例子来自(ab)使用std::function: std::function<bool(T, T)> cmp1 = std
auto
类型提高了正确性和可维护性。我已经读到它也可以提高性能(由Herb Sutter编写),但是我错过了一个很好的解释
如何提高性能auto
- 有人能举个例子吗
auto
推导初始化表达式的类型,所以不涉及类型转换。与模板算法相结合,这意味着您可以得到比自己创建类型更直接的计算——尤其是在处理无法命名其类型的表达式时
一个典型的例子来自(ab)使用std::function
:
std::function<bool(T, T)> cmp1 = std::bind(f, _2, 10, _1); // bad
auto cmp2 = std::bind(f, _2, 10, _1); // good
auto cmp3 = [](T a, T b){ return f(b, 10, a); }; // also good
std::stable_partition(begin(x), end(x), cmp?);
这始终是一个引用,绑定到函数调用表达式的值,并且从不构造任何其他对象。如果您不知道返回值的类型,可能会被迫通过
t&&f=makathing()
之类的方式构造一个新对象(可能是临时对象)。(此外,auto&&
甚至在返回类型不可移动且返回值为prvalue时工作。)auto
可以通过避免无提示隐式转换来帮助提高性能。我发现一个引人注目的例子如下
std::map<Key, Val> m;
// ...
for (std::pair<Key, Val> const& item : m) {
// do stuff
}
类型转换是允许的隐式转换,其原因与您可以将常量键
转换为键
的原因相同,但我们必须构造新类型的临时值才能实现这一点。因此,我们的循环实际上是:
std::pair<Key, Val> __tmp = *iter; // construct a temporary of the correct type
std::pair<Key, Val> const& item = __tmp; // then, take a reference to it
刚刚为我们保存了大量副本-现在引用的类型与初始值设定项类型匹配,因此不需要临时或转换,我们可以直接引用 有两类
auto
可以避免类型擦除。有不可命名的类型(如lambdas)和几乎不可命名的类型(如std::bind
或其他类似表达式模板的结果)
如果没有auto
,您最终必须键入擦除数据的内容,例如std::function
。类型擦除有成本
std::function<void()> task1 = []{std::cout << "hello";};
auto task2 = []{std::cout << " world\n";};
如果expression()
返回Bar const&
或Bar
甚至Bar&
,则将编译,其中Foo
可以从Bar
构造。将创建一个临时的Foo
,然后绑定到f
,其生存期将延长到f
消失
程序员可能是指Bar const&f
,不打算在那里复制,但无论如何都要复制
最常见的例子是*std::map::const_迭代器
的类型,它是std::pair const&
而不是std::pair const&
,但错误是一类以性能为代价的错误。您可以从std::pair
构造std::pair
。(地图上的键是const,因为编辑它是个坏主意)
Barry和KerrekSB都在他们的回答中首先阐明了这两个原则。这只是试图在一个答案中突出这两个问题,措辞针对问题,而不是以示例为中心。现有的三个答案给出了使用
auto
有助于有效“提高性能”的示例
硬币有另一面。对具有不返回基本对象的运算符的对象使用auto
,可能会导致错误的代码(仍然是可编译和可运行的)。例如,询问如何使用auto
使用特征库得出不同(不正确)的结果,即以下几行
const auto resAuto = Ha + Vector3(0.,0.,j * 2.567);
const Vector3 resVector3 = Ha + Vector3(0.,0.,j * 2.567);
std::cout << "resAuto = " << resAuto <<std::endl;
std::cout << "resVector3 = " << resVector3 <<std::endl;
const auto resAuto=Ha+Vector3(0,0,j*2.567);
常量向量3 resVector3=Ha+Vector3(0,0,j*2.567);
std::看不出哪一个谈论避免意外的隐式转换,例如从小工具到小工具。这不是一个常见的问题。您是否接受“使其不太可能无意中悲观化”作为一种性能改进?仅在将来清理代码的性能,可能是因为我们需要一个简短的答案:不,如果您很好。它可以防止“noobish”错误。C++有一个学习曲线,它会杀死那些根本不做它的人。“巴里,你能解释为什么编译器会很高兴地复制而不是抱怨试图处理<代码> STD::配对const和< /> >作为<代码> STD::配对const和< /Cord>?C++11新手,不确定和auto
的范围如何发挥作用。@Barry感谢您的解释。这就是我遗漏的部分——出于某种原因,我认为你不可能不断地引用一个临时文件。但是你当然可以——它将在其作用域的末尾不再存在。@barry我明白了,但问题是,没有一个答案能够涵盖使用auto
来提高性能的所有原因。所以我将用我自己的话写在下面。我仍然不认为这是“auto
提高性能”的证据。这只是一个例子,“自动<代码>有助于防止程序员错误破坏性能”。我认为,两者之间存在着微妙但重要的区别。不过,+1。这就是使用auto
的“避免类型擦除”原因。你的另一个变体是“避免意外复制”,但需要修饰;为什么auto
比在那里简单地键入类型更快?(我认为答案是“你把类型弄错了,它会自动转换”)这使得它成为巴里答案中解释得不太清楚的例子,不是吗?也就是说,有两种基本情况:自动避免类型擦除和自动避免意外转换的静默类型错误,这两种情况都有运行时成本。“不仅调用不能内联”——为什么?您的意思是,如果std::bind
、std::function
和std::stabl的相关专业化,原则上有什么东西可以防止调用在数据流分析后被解除虚拟化
std::pair<Key, Val> __tmp = *iter; // construct a temporary of the correct type
std::pair<Key, Val> const& item = __tmp; // then, take a reference to it
for (auto const& item : m) {
// do stuff
}
std::function<void()> task1 = []{std::cout << "hello";};
auto task2 = []{std::cout << " world\n";};
Foo const& f = expression();
const auto resAuto = Ha + Vector3(0.,0.,j * 2.567);
const Vector3 resVector3 = Ha + Vector3(0.,0.,j * 2.567);
std::cout << "resAuto = " << resAuto <<std::endl;
std::cout << "resVector3 = " << resVector3 <<std::endl;