我可以看到为什么在 C + + 11 中的auto类型提高了正确性和可维护性。我已阅读,它还可以提高性能 (几乎总是自动通过等 Sutter),但我错过了很好的解释了。

  • 如何可以auto提高性能?
  • 任何人都可以给出示例?
2015-09-10 19:30:37
问题评论:

请参阅herbsutter.com/2013/06/13/...谈到避免意外的隐式转换,如在对构件的小工具。它不是一个常见的问题。

不要接受"就不太可能于无意中 pessimize"作为提高性能?

Perfomance 的代码清理以后只,也许

我们需要一个简短的回答︰ 没有,如果你很好。它可以防止 noobish 错误。C + + 的删除那些没有做它毕竟学习曲线。

回答:

auto能够帮助避免静默的隐式转换的性能。以下是的示例找到令人信服。

std::map<Key, Val> m;
// ...

for (std::pair<Key, Val> const& item : m) {
    // do stuff
}

请参阅该 bug?这里我们,认为我们像通过 const 引用映射中采取的每一项,使用新的区域的表达式,以便使我们的目的,清除,但实际上对于我们从中复制的每个元素。这是因为std::map<Key, Val>::value_typestd::pair<const Key, Val>,不std::pair<Key, Val>因此,当我们 (隐式) 有︰

std::pair<Key, Val> const& item = *iter;

而不是采用对现有对象的引用并将其保留在此,我们必须执行类型转换。允许您采取 const 引用到不同类型的对象 (或临时),只要没有隐式转换可用,例如︰

int const& i = 2.0; // perfectly OK

类型转换为相同的原因可以将const Key转换为一个Key,但我们必须以允许,构造一种新类型的临时的允许进行隐式转换。因此,实际上我们循环执行的操作︰

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

当然,其实是__tmp对象不存在,它就是只图 (事实上未命名的临时只绑定到item)。

只需将更改为︰

for (auto const& item : m) {
    // do stuff
}

不仅仅被节省了我们大量的副本-现在引用的类型匹配的初始值设定项类型,因此无法临时或转换是必需的只是我们所能做的直接引用。

@Barry 可以解释为什么编译器会不假思索地使副本而不是抱怨试图将std::pair<const Key, Val> const &std::pair<Key, Val> const &对 C + + 11,不清楚如何范围-为并auto播放到此。

@Barry 感谢解释。这就是我遗失的部分由于某种原因,我认为您不能有一个临时的常量引用。但当然可以-它只会停止存在其范围的末尾。

@barry 得到您,但问题是随后没有涵盖所有使用auto提高性能的原因的答案。因此我将它在编写以下我自己文字。

我仍然不认为这是证明auto提高性能"。它只是一个示例,auto有助于防止破坏性能的程序员错误"。提交是细微但却很重要的两个区别。尽管如此,+ 1。

因为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?);

cmp2cmp3,整个算法可以内联比较呼叫,而如果构建一个std::function对象,不只可以调用不是内联的但还需要经过多态类型被擦除内部函数包装的查找。

另一个变量,该变量在此主题上的是可以说︰

auto && f = MakeAThing();

这始终是一个引用,并绑定到值的函数调用表达式,并永远不会构造任何其他对象。如果您不知道返回的值类型,您可能会被迫通过类似 (也许作为一个临时) 构造一个新对象T && f = MakeAThing()(此外,auto &&时的返回类型不是可移动和返回的值是 prvalue,甚至工作。)

因此,这是使用auto"避免类型擦除"原因。您其他变体是"避免意外拷贝",但需要修饰符;为什么那样auto授予您速度只需键入的类型那里过?(我认为答案是"您获得的类型不正确,并悄悄将")这使它 Barry 的回答不太正确解释了的示例不?例如,有两种基本情况︰ 自动以避免类型擦除,并自动以避免意外地转换,这两种具有运行时成本无提示的类型错误。

"不只该调用不能内联"-然后为什么是?指的东西会阻止正在 devirtualized 后数据流动分析,如果std::bindstd::functionstd::stable_partition的相关专项已全部被内联调用的原则?或者,只是,在实践中没有 c + + 编译器会内联足够积极来理清混乱?

@SteveJessop︰ 主要是后者的经过std::function构造函数后,它会非常复杂,要看透的实际调用,尤其是在小型函数 optimisations (因此您确实不想 devirtualization)。当然原则上一切都是为-如果...

有两种类别。

auto可以避免类型擦除。有 unnamable 类型 (例如 lambda) 和几乎 unnamable 类型 (如std::bind或类似事项的其他表达式模板的结果)。

auto,结束了无需键入擦除数据,直至std::function类似。类型擦除已成本。

std::function<void()> task1 = []{std::cout << "hello";};
auto task2 = []{std::cout << " world
";};

task1具有类型擦除开销 — 堆可能分配困难内联,和虚函数表调用开销。task2也没有。Lambda 时需要自动或其他形式的类型推导存储而无需类型擦除;其他类型可以是如此的复杂,它们只需要在实践中。

第二,您可以获得类型错误。在某些情况下,错误类型似乎是完美的但将导致复制过程。

Foo const& f = expression();

将编译如果返回expression() Bar const&Bar或甚至Bar&,可用于Foo构造从Bar一个临时Foo将被创建,然后绑定到f,并将延长其生命周期内,直到f消失为止。

程序员可能意味着Bar const& f并不打算制作一个副本,但无论制作副本。

最常见的示例是一种*std::map<A,B>::const_iterator,即std::pair<A const, B> const&std::pair<A,B> const&,但错误是以静默方式成本性能的错误类别。您可以构建从std::pair<A, B> std::pair<const A, B>(一个映射的键是常数,因为编辑它是个好主意)

@Barry 和 @KerrekSB 首先阐释了自己的答案在这两个原则。这是只是试图以突出显示一个答案,用来解决问题的目的的措辞,而不是由中心示例中的两个问题。

现有的三个答案就举出一些例子,使用auto帮助"使得它不太可能于无意中 pessimize"有效地使其"改善"。

没有到另一面的硬币。auto使用运算符不返回的基本对象的对象可能会导致不正确的 (仍可编译和运行) 代码。例如,此问题会询问如何使用auto给予不同 (不正确) 的结果,使用 Eigen 库,以下命令行

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;

导致不同的输出。当然,这主要是因为 Eigens 迟缓计算中,但该代码是/应该是透明的 (库) 用户。

虽然没有已极大地影响性能在这里,使用auto避免无意 pessimization 可能会过早的优化,为机密或至少错误;)。

请输入您的翻译

Can the use of C++11's 'auto' improve performance?

确认取消