在使用range for循环处理std::initializer_list元素时,使用“const auto&”是一种好的做法吗?

18

我正在阅读来自C++ Primer 5th (6.2.6.带有可变参数的函数)的一段代码:

void error_msg(ErrCode e, initializer_list<string> il)
{
    cout << e.msg() << ": ";
    for (const auto &elem : il)
        cout << elem << " ";
    cout << endl;
}

我总是直接在范围 for 中使用 auto,像这样:

for (auto &elem : il)

但我以前从未见过 const auto&。我知道一个 initializer_list 中的元素始终是常量值。这是使用 const auto& 的原因吗?

  • 这种方式和我的旧方式有什么区别?
  • 在这种情况下使用 "const auto&" 是一个好习惯吗?

4
在C++17中,您可以使用for (elem : il)的语法。这是我的首选,因为它易于编写且功能强大(某些编译器已经支持此语法)。 - oblitum
2
for (auto elem : il) 会不必要地创建每个元素的临时副本。 - Siyuan Ren
2
@pezy:这并不是“真的很酷”。在其他某些语言中可能会很“酷”,但它违反了许多长期存在的C++范例,导致了一种完全不一致的语言,不知道自己想要成为什么样的语言。 - Lightness Races in Orbit
1
@sp2danny:这违反了许多长期存在的C ++范例,导致了一种完全不一致的语言,不知道它想成为什么。 - Lightness Races in Orbit
5
那个“for (e : r)”的提案暂时被拒绝了,不会进入C++17。 - Ela782
显示剩余9条评论
3个回答

30

这是一个良好的实践,因为意图明确且可以防止意外更改破坏您的代码。

各种形式的基于范围的for循环之间的区别:

  • for (auto elem : il) 将创建每个元素的临时副本。通常效率较低。

  • for (auto& elem: il) 不会创建副本,并允许您修改元素(如果底层容器允许,例如不是const)。但它不能绑定到右值引用,因此无法用于返回代理对象的容器(例如std::vector<bool>)。

  • for (const auto& elem: il) 也不会创建副本,并且不允许进行任何修改。这可以防止意外修改并清楚地表示您的意图。

  • for (auto&& elem: il) 自动推断出elem的正确类型,无论是左值、const左值还是右值引用。一个标准提案N3994,已经被clang实现,将其简化为形式for (elem: il)


在我看来,第一个的意图是“不要改变”,第二个是“如果允许,你可以改变”。对吗?(所以,如果只是打印,我们选择了for(auto elem : il)。) - pezy
3
如果你只需要打印,为什么还要复制呢? - Siyuan Ren
是的。但是在C++ Primer 5th中,几乎所有的打印代码都使用for (auto elem : arr),为什么?有什么意义吗? - pezy
4
在《C++ Primer第五版》中的确切位置上,“for (auto elem : arr)”出现时,“elem”的类型是“int”。 “int”易于复制,而“std::string”则不然。 - Siyuan Ren
非常感谢,我终于明白了。非常感谢! - pezy
哇,我不知道有这个提案。他们简化语言真的很好。虽然,我更喜欢默认使用const(对于lambda引用捕获也是如此)。 - Viktor Sehr

23

由于 std::initializer_list 中的元素是 const 的,因此使用 auto& elemconst auto& elem 进行迭代具有相同的语义。编写 const 的优点在于它明确告诉阅读代码的任何人内容不会被修改(即使无论如何也不能修改内容)。


谢谢回答,你的意思是只添加 const 是为了可读性?那我也可以这样做:const auto elem : il?还是一样的吗? - pezy
3
在按值迭代时,“const”的含义是不同的。思考一下函数的按值传递和按引用传递,就会明白其中的道理。 - Brian Bi

3

对我来说这是好的:

  • 使它明确。
  • 在这种情况下,冗余被编译器消除。
  • 如果您替换为另一个容器,您仍将拥有常量,不会被静默修改。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接