C++ 新关键字“自动”;什么时候应该用它来声明一个变量类型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6900459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
The new keyword "auto"; When should it be used to declare a variable type?
提问by Martin York
Possible Duplicate:
How much is too much with C++0x auto keyword
可能的重复:
C++0x auto 关键字太多了
Have we (as a community) had enough experience to determine when and/or whether auto is being abused?
我们(作为一个社区)是否有足够的经验来确定汽车何时和/或是否被滥用?
What I am really looking for is a best practices guide on
我真正在寻找的是最佳实践指南
- when to use auto
- when it should be avoided
- 何时使用自动
- 什么时候应该避免
Simple rules of thumb that can quickly be followed in 80% of cases.
可以在 80% 的情况下快速遵循的简单经验法则。
As a context this question is sparked by my response here
作为上下文,这个问题是由我在这里的回答引发的
回答by Nawaz
I think when the type is very well-known amongst the co-programmers who work (or would work) in your project, then auto
can be used, such as in the following code:
我认为当该类型在您的项目中工作(或将工作)的协同程序员中非常知名时,则auto
可以使用,例如在以下代码中:
//good : auto increases readability here
for(auto it = v.begin(); it != v.end(); ++it) //v is some [std] container
{
//..
}
Or, more generally,
或者,更一般地说,
//good : auto increases readability here
for(auto it = std::begin(v); it != std::end(v); ++it)//v could be array as well
{
//..
}
But when the type is not very well-known and infrequently used , then I think auto
seems to reduce readability, such as here:
但是当类型不是很出名并且很少使用时,那么我认为auto
似乎降低了可读性,例如这里:
//bad : auto decreases readability here
auto obj = ProcessData(someVariables);
While in the former case, the usage of auto
seems very good and doesn't reduce readability, and therefore, can be used extensively, but in the latter case, it reduces readabilty and hence shouldn't be used.
虽然在前一种情况下,使用auto
似乎很好,不会降低可读性,因此可以广泛使用,但在后一种情况下,它降低了可读性,因此不应使用。
Another place where auto
can be used is when you use new
1or make_*
functions , such as here:
另一个auto
可以使用的地方是当您使用new
1或make_*
functions 时,例如这里:
//without auto. Not that good, looks cumbersome
SomeType<OtherType>::SomeOtherType * obj1 = new SomeType<OtherType>::SomeOtherType();
std::shared_ptr<XyzType> obj2 = std::make_shared<XyzType>(args...);
std::unique_ptr<XyzType> obj2 = std::make_unique<XyzType>(args...);
//With auto. good : auto increases readability here
auto obj1 = new SomeType<OtherType>::SomeOtherType();
auto obj2 = std::make_shared<XyzType>(args...);
auto obj3 = std::make_unique<XyzType>(args...);
Here it is very good, as it reduces the use of keyboard, without reducing the readability, as anyone can know the type of objectsbeing created, just by looking at the code.
这里非常好,因为它减少了键盘的使用,而不会降低可读性,因为任何人都可以通过查看代码知道正在创建的对象的类型。
1. Avoid using new
and raw-pointers though.
1. 避免使用new
和原始指针。
Sometime, the type is so irrelevant that the knowledge of the type is not even needed, such as in expression template; in fact, practicallyit is impossible to write the type (correctly), in such cases auto
is a relief for programmers. I've written expression template library which can be used as:
有时,类型是如此无关紧要以至于甚至不需要类型的知识,例如在表达式模板中;实际上,实际上不可能(正确地)编写类型,在这种情况下auto
对程序员来说是一种解脱。我编写了表达式模板库,可用作:
foam::composition::expression<int> x;
auto s = x * x; //square
auto c = x * x * x; //cube
for(int i = 0; i < 5 ; i++ )
std::cout << s(i) << ", " << c(i) << std::endl;
Output:
输出:
0, 0
1, 1
4, 8
9, 27
16, 64
Now compare the above code with the following equivalentcode which doesn't use auto
:
现在将上面的代码与以下不使用的等效代码进行比较auto
:
foam::composition::expression<int> x;
//scroll horizontally to see the complete type!!
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply>> s = x * x; //square
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply> >, foam::composition::expression<int>, foam::operators::multiply>> c = x * x * x; //cube
for(int i = 0; i < 5 ; i++ )
std::cout << s(i) << ", " << c(i) << std::endl;
As you can see, in such cases auto
makes your life exponentially easier. The expressions used above are very simple; think about the type of some more complex expressions:
如您所见,在这种情况下auto
,您的生活会变得更加轻松。上面使用的表达式非常简单;想想一些更复杂的表达式的类型:
auto a = x * x - 4 * x + 4;
auto b = x * (x + 10) / ( x * x+ 12 );
auto c = (x ^ 4 + x ^ 3 + x ^ 2 + x + 100 ) / ( x ^ 2 + 10 );
The type of such expressions would be even more huge and ugly, but thanks to auto
, we now can let the compiler infer the type of the expressions.
这种表达式的类型会更加庞大和丑陋,但多亏了auto
,我们现在可以让编译器推断表达式的类型。
So the bottomline is: the keyword auto
might increase or decreaseclarity and readability of your code, depending on the context. If the context makes it clear what typeit is, or at least how it should be used (in case of standard container iterator) or the knowledge of the actual type is not even needed (such as in expression templates), then auto
should be used, and if the context doesn't make it clear and isn't very common (such as the second case above), then it should better be avoided.
所以底线是:关键字auto
可能会增加或降低代码的清晰度和可读性,具体取决于上下文。如果上下文清楚它是什么类型,或者至少应该如何使用它(在标准容器迭代器的情况下)或者甚至不需要实际类型的知识(例如在表达式模板中),那么auto
应该使用,并且如果上下文没有说清楚并且不是很常见(例如上面的第二种情况),那么最好避免使用。
回答by spraff
Easy. Use it when you don't carewhat the type is. For example
简单。当您不在乎类型是什么时使用它。例如
for (auto i : some_container) {
...
All I care about here is that i
is whatever's in the container.
我在这里关心的是i
容器中的任何东西。
It's a bit like typedefs.
它有点像 typedef。
typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;
Here, I don't care whether h
and w
are floats or doubles, only that they are whatever type is suitable to express heights and weights.
在这里,我不在乎h
andw
是 floats 还是 doubles,只关心它们是适合表达 heights 和 weights 的任何类型。
Or consider
或者考虑
for (auto i = some_container .begin (); ...
Here all I care about is that it's a suitable iterator, supporting operator++()
, it's kind of like duck typing in this respect.
这里我关心的是它是一个合适的迭代器,支持operator++()
,在这方面有点像鸭子打字。
Also the type of lambdas can't be spelled, so auto f = []...
is good style. The alternative is casting to std::function
but that comes with overhead.
lambdas 的类型也不能拼写,所以auto f = []...
是好的风格。另一种方法是强制转换为,std::function
但这会带来开销。
I can't really conceive of an "abuse" of auto
. The closest I can imagine is depriving yourself of an explicit conversion to some significant type -- but you wouldn't use auto
for that, you'd construct an object of the desired type.
我真的无法想象“滥用” auto
. 我能想象的最接近的是剥夺自己对某种重要类型的显式转换——但你不会使用auto
它,你会构造一个所需类型的对象。
If you canremove some redundancy in your code without introducing side effects, then it mustbe good to do so.
如果您可以在不引入副作用的情况下删除代码中的一些冗余,那么这样做一定很好。
回答by Konrad Rudolph
I'd apply the same rule as for var
in C#: use it liberally. It increasesreadability. Unless the type of a variable is actually important enough to be stated explicitly, in which cases this should be done (duh).
我会应用与var
在 C# 中相同的规则:自由使用它。它增加了可读性。除非变量的类型实际上足够重要以明确说明,否则应该这样做(废话)。
Still, I maintain that (especially in statically typed languages) the compiler is much better at tracking types for us than we are. Most of the time, the exacttype isn't terribly important anyway (otherwise interfaces wouldn't work in practice). It's more important to be aware of which operations are permitted. Context should tell us that.
尽管如此,我仍然认为(尤其是在静态类型语言中)编译器在为我们跟踪类型方面比我们好得多。大多数时候,确切的类型无论如何都不是很重要(否则接口在实践中将无法工作)。了解允许哪些操作更为重要。上下文应该告诉我们这一点。
Furthermore, auto
can actually prevent bugs, by preventing unwanted implicit conversions in initialisations. Generally, the statement Foo x = y;
will perform an implicit conversion if y
isn't of type Foo
and an implicit conversion exists. This is the reason to avoid having implicit conversions in the first place. Unfortunately, C++ has much too many of them already.
此外,通过防止初始化中不需要的隐式转换,auto
实际上可以防止错误。通常,Foo x = y;
如果y
不是类型Foo
并且存在隐式转换,则该语句将执行隐式转换。这就是首先要避免隐式转换的原因。不幸的是,C++ 已经有太多这样的东西了。
Writing auto x = y;
will prevent this problem in principle.
写作auto x = y;
将在原则上防止这个问题。
On the other hand, it should be clear that when I'm performing calculations that assume this or that number of bytes in an integer, the explicit type of the variable must be known and should be clearly stated.
另一方面,应该清楚的是,当我执行假定整数中有这个或那个字节数的计算时,必须知道变量的显式类型并且应该清楚地说明。
Not all cases are as clear cut but I maintain that most are, and that
并非所有案例都如此清晰,但我认为大多数都是如此,而且
- in most cases it's easy to see whether an explicit type needs to be known, and
- the need for explicit types is comparatively rare.
- 在大多数情况下,很容易看出是否需要知道显式类型,并且
- 显式类型的需求相对较少。
Eric Lippert, principal developer on the C# compiler team, has stated much the same with regards to var
.
C# 编译器团队的首席开发人员Eric Lippert对var
.
回答by Jerry Coffin
I think the answer to your first question is sort of no. We know enough to put together some guidelines about when to use or avoid auto
, but they still leave quite a few cases where the best we can currently say is that we can't yet give much in the way of objective advice about them.
我认为你的第一个问题的答案是否定的。我们知道足够多的关于何时使用或避免使用 的指导方针auto
,但它们仍然留下了相当多的情况,我们目前可以说的最好的情况是我们还不能提供关于它们的客观建议。
The obvious case where you nearly haveto use it is in a template when you want (for example) the proper type to hold the result of some operation on two generic parameters. In a case like this, the only possibility of abuse wouldn't really be abuse of auto
itself, but whether the general type of operation you're doing (or type of template you're writing, etc.) is something you'd be better off avoiding.
当您想要(例如)正确的类型来保存对两个泛型参数的某些操作的结果时,您几乎必须使用它的明显情况是在模板中。在这种情况下,滥用的唯一可能性并不是滥用auto
本身,而是您正在执行的一般操作类型(或您正在编写的模板类型等)是否是您想要的最好避免。
There are also at least a few situations where you clearly need to avoid auto
. If you're using something like a proxy type where you're depending on the conversion from proxy->target to do part of the job at hand, auto
will (attempt to) create a target of the same type as the source so that conversion won't happen. In some cases, that may just delay the conversion, but in others it won't work at all (e.g., if the proxy type doesn't support assignment, which is often the case).
至少还有一些情况是您显然需要避免的auto
。如果您使用的是代理类型之类的东西,您依赖从代理-> 目标的转换来完成手头的部分工作,auto
将(尝试)创建与源相同类型的目标,以便转换不会发生。在某些情况下,这可能只是延迟转换,但在其他情况下它根本不起作用(例如,如果代理类型不支持分配,这通常是这种情况)。
Another example would be when you need to assure that a particular variable has a specific type for the sake of something like an external interface. Just for example, consider applying the network mask to an IP (v4) address. For the sake of argument, let's assume you're working with the individual octets of the address (e.g., representing each as an unsigned char
), so we end up with something like octets[0] & mask[0]
. Thanks to C's type promotion rules, even if both operands are unsigned char
s, the result is typically going to be int
. We needthe result to be an unsigned char
though (i.e., one octet) not an int
(typically 4 octets) though. As such, in this situation, auto
would almost certainly be inappropriate.
另一个例子是当您需要确保特定变量具有特定类型时,以便于外部接口之类的东西。例如,考虑将网络掩码应用于 IP (v4) 地址。为了便于论证,让我们假设您正在处理地址的各个八位字节(例如,将每个八位字节表示为unsigned char
),因此我们最终得到类似octets[0] & mask[0]
. 由于 C 的类型提升规则,即使两个操作数都是unsigned char
s,结果通常也会是int
。我们需要结果是一个unsigned char
虽然(即一个八位字节)而不是一个int
(通常是 4 个八位字节)虽然。因此,在这种情况下,auto
几乎肯定是不合适的。
That still leaves a lot of cases where it's a judgement call though. My own tendencyfor these cases is to treat auto
as the default, and only use an explicit type in cases that are at least a little like the latter case I've cited above -- even if a particular type isn't neededfor correct operation that I really wanta particular type, even if that might involve an implicit conversion.
尽管如此,这仍然留下了很多需要判断的情况。对于这些情况,我自己倾向于将其auto
视为默认值,并且仅在至少有点像我上面引用的后一种情况的情况下才使用显式类型——即使正确操作不需要特定类型我真的想要一个特定的类型,即使这可能涉及隐式转换。
My guess (but it is just a guess) is that over time, I'll probablytend even more in that direction. As I get more accustomed to the compiler picking out types, I'll find that a fair number of cases where I currently thinkI should specify the type, I really don't need to and the code will be just fine.
我的猜测(但只是猜测)是随着时间的推移,我可能会更倾向于这个方向。随着我越来越习惯于编译器挑选类型,我会发现在我目前认为应该指定类型的相当多的情况下,我真的不需要,代码会很好。
I suspect a lot of us (and the older/more experienced we are, probably the worse we'll be about it) will use explicit types for reasons that ultimately trace back to some feeling about performance, and believing that our choice will improve performance. Part of the time we mayeven be right -- but as most of us with that much experience have found, our guesses are often wrong (especially when they're based on implicit assumptions), and compilers and processors generally get better at such things over time as well.
我怀疑我们中的很多人(以及我们越老/越有经验,可能越糟糕)会出于最终追溯到对性能的某种感觉的原因而使用显式类型,并相信我们的选择会提高性能. 有时我们甚至可能是对的——但正如我们大多数拥有丰富经验的人所发现的那样,我们的猜测往往是错误的(尤其是当它们基于隐式假设时),并且编译器和处理器通常在这些事情上做得更好随着时间的推移。
回答by Luc Danton
I've used languages with full type inference. I see no reason not to put auto
everywhere it's technically possible*. In fact I may have already written auto i = 0;
, where int
is one character shorter than auto
. I'm not even sure that I did because the bottom is: I don't care for manifest typing.
我使用过具有完整类型推断的语言。我认为没有理由不把auto
它放在技术上可行的任何地方*。事实上我可能已经写过auto i = 0;
,哪里int
比auto
. 我什至不确定我这样做了,因为底部是:我不关心清单输入。
*: for instance auto int[] = { 0, 1, 2, 3 }
doesn't work.
*:例如auto int[] = { 0, 1, 2, 3 }
不起作用。
回答by Will03uk
Only use it with long repetitive types such as long templates and lambda function types. Try to avoid it if you can to make things clear.
仅将其用于长重复类型,例如长模板和 lambda 函数类型。如果可以的话,尽量避免它。