我一直在使用c++ 11标准中提供的新的auto关键字来处理复杂的模板类型,我相信它就是为这个目的设计的。但我也用它来做以下事情:
auto foo = std::make_shared<Foo>();
更令人怀疑的是:
auto foo = bla(); // where bla() return a shared_ptr<Foo>
我还没有看到很多关于这个话题的讨论。auto似乎被滥用了,因为类型通常是一种文档和完整性检查的形式。你在使用auto方面的界限在哪里,这个新功能的推荐用例是什么?
澄清一下:我并不是在寻求哲学观点;我要求标准委员会对这个关键字的预期使用,可能还会对如何在实践中实现预期使用发表评论。
c++程序的一个主要问题是允许你使用未初始化的变量。这导致了我们讨厌的非确定性程序行为。应该注意的是,现代编译器现在抛出适当的/message警告消息,如果程序累了使用它。
为了说明这一点,考虑下面的c++程序:
int main() {
int x;
int y = 0;
y += x;
}
如果我使用现代编译器(GCC)编译这个程序,它会给出警告。这样的警告可能并非如此
如果我们使用的是真正复杂的产品代码,这是非常明显的。
main.cpp:在函数'int main()'中:
Main.cpp:4:8:警告:'x'在此函数中未初始化
(-Wuninitialized)
Y += x;
^
=================================================================================
现在如果我们改变我们的程序,使用auto,然后编译,我们得到如下:
int main() {
auto x;
auto y = 0;
y += x;
}
main.cpp:在函数'int main()'中:
Main.cpp:2:10:错误:声明'auto x'没有初始化式
汽车x;
^
对于auto,不可能使用未初始化的变量。如果我们开始使用auto,这是我们可以(免费)获得的主要优势。
c++专家Herb Shutter在他的CppCon14演讲中解释了这个概念和其他伟大的现代c++概念:
回归基本!现代c++风格要点
在c++和超越2012的Ask Us Anything小组中,Andrei Alexandrescu、Scott Meyers和Herb Sutter就何时使用和不使用auto进行了一次精彩的交流。跳到25:03分钟进行4分钟的讨论。这三位演讲者都给出了很好的观点,应该记住什么时候不使用auto。
我非常鼓励人们得出自己的结论,但我的结论是在任何地方都要使用auto,除非:
这会影响可读性
关心自动类型转换(例如,从构造函数,赋值,模板中间类型,整数宽度之间的隐式转换)
自由地使用explicit有助于减少对后者的关注,这有助于最大限度地减少前者成为问题的时间。
换句话说,Herb说,“如果你不做X, Y和Z,用auto。了解X, Y和Z是什么,然后在其他地方使用auto。”
c++程序的一个主要问题是允许你使用未初始化的变量。这导致了我们讨厌的非确定性程序行为。应该注意的是,现代编译器现在抛出适当的/message警告消息,如果程序累了使用它。
为了说明这一点,考虑下面的c++程序:
int main() {
int x;
int y = 0;
y += x;
}
如果我使用现代编译器(GCC)编译这个程序,它会给出警告。这样的警告可能并非如此
如果我们使用的是真正复杂的产品代码,这是非常明显的。
main.cpp:在函数'int main()'中:
Main.cpp:4:8:警告:'x'在此函数中未初始化
(-Wuninitialized)
Y += x;
^
=================================================================================
现在如果我们改变我们的程序,使用auto,然后编译,我们得到如下:
int main() {
auto x;
auto y = 0;
y += x;
}
main.cpp:在函数'int main()'中:
Main.cpp:2:10:错误:声明'auto x'没有初始化式
汽车x;
^
对于auto,不可能使用未初始化的变量。如果我们开始使用auto,这是我们可以(免费)获得的主要优势。
c++专家Herb Shutter在他的CppCon14演讲中解释了这个概念和其他伟大的现代c++概念:
回归基本!现代c++风格要点
我指出的一个危险是在引用方面。
如。
MyBigObject& ref_to_big_object= big_object;
auto another_ref = ref_to_big_object; // ?
问题是,在这种情况下,another_ref实际上不是一个引用,它是MyBigObject而不是MyBigObject&。你最终复制了一个大对象而没有意识到它。
如果你直接从一个方法中得到一个引用,你可能不会考虑它实际上是什么。
auto another_ref = function_returning_ref_to_big_object();
你需要"auto&"或者"const auto&"
MyBigObject& ref_to_big_object= big_object;
auto& another_ref = ref_to_big_object;
const auto& yet_another_ref = function_returning_ref_to_big_object();
一件容易的事。当你不关心是什么类型时使用它。例如
for (const auto & i : some_container) {
...
这里我只关心I是容器里的东西。
它有点像typedefs。
typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;
这里,我不关心h和w是浮点数还是双精度浮点数,只关心它们是任何适合表示高度和权重的类型。
或者考虑
for (auto i = some_container .begin (); ...
这里我只关心它是一个合适的迭代器,支持运算符++(),在这方面有点像鸭子类型。
此外,lambdas的类型不能拼写,因此auto f =[]…是好的风格。另一种方法是强制转换为std::function,但这会带来开销。
我真的无法想象对汽车的“滥用”。我能想到的最接近的是剥夺你自己到一些重要类型的显式转换——但你不会使用auto,你会构造一个所需类型的对象。
如果您可以在不引入副作用的情况下删除代码中的一些冗余,那么这样做一定是好的。
反例(借用别人的回答):
auto i = SomeClass();
for (auto x = make_unsigned (y); ...)
这里我们确实关心类型是什么,所以我们应该写Someclass i;And for(unsigned x = y;…