C ++自动与自动


88

创建局部变量时,使用(const) auto&auto是否正确?

例如:

SomeClass object;
const auto result = object.SomeMethod();

要么 const auto& result = object.SomeMethod();

SomeMethod()返回非原始值的地方-可能是另一个用户定义的类型。我的理解是const auto& result正确的,因为SomeMethod()返回的结果将为返回的类型调用复制构造函数。如果我错了,请纠正我。

原始类型呢?我认为const auto sum = 1 + 2;是正确的。

这是否也适用于基于范围的for循环?

for(const auto& object : objects)

1
我强烈建议您阅读以下内容:safaribooksonline.com/library/view/effective-modern-c/…前两章是免费的,介绍了模板类型推导,这实际上是如何auto工作的(除了initializer_lists的特殊情况,(在模板上下文中未推演),然后auto键入推演。
vsoftco

Answers:


102

autoauto &&涵盖大多数情况:

  • 使用auto时,你需要一个本地副本。这将永远不会产生参考。复制(或移动)构造函数必须存在,但是由于复制省略优化,它可能不会被调用。

  • 使用auto &&时,你不在乎,如果对象是本地的。从技术上讲,这将始终产生引用,但是如果初始化器是临时的(例如,函数按值返回),则其行为本质上将类似于您自己的本地对象。

    同样,auto &&也不保证对象是可修改的。给定一个const对象或引用,它将得出结论const。但是,在给定特定上下文的情况下,通常假定可修改性。

auto &auto const &更具体一些:

  • auto &保证您与其他共享变量。它始终是参考,绝不是临时的。

  • auto const &类似于auto &&,但提供只读访问权限。

对于原始/非原始类型呢?

没有区别。

这是否也适用于基于范围的for循环?

是。应用上述原则,

  • 使用auto &&了修改能力和内环路的序列丢弃值。(也就是说,除非容器提供了只读视图,例如std::initializer_list,在这种情况下,它将实际上是一个auto const &。)
  • 用于auto &以有意义的方式修改序列的值。
  • 使用auto const &的只读访问。
  • 使用auto工作与(修改)的副本。

您还提到auto const了没有参考。这种方法有效,但不是很常用,因为对您已经拥有的内容进行只读访问几乎没有好处。


萨特(Sutter)说,自动&跟踪稳定性
杰西·

1
@JessePepper是的。(不过,诉诸权威有点奇怪。)您是否指的是这一部分?
Potatoswatter

从本质上来说auto&似乎是一个不错的选择。但是,const auto&当您要添加不存在的constness时使用。 auto&&是用于转发,我认为这种情况比Sutter认为的发生得更多。例如,您可能想要存储一个返回值auto&&,然后将其“转发”到两件事上,例如std :: cout,以查看调试值并将其传递给其他函数。我过去经常使用auto &&,但是在做一些意外的事情时却被它咬了一两次。希望我能更多留意出了什么问题!
杰西·佩珀

@JessePepper是的,auto&&与缺少语言功能有关,该功能允许将任何语句分成较小的语句。缺少的部分是生命周期的延长……我在解决这个问题上付出了很多努力,但没人注意到。不要过多地投入库存:)
Potatoswatter

关于自动常量:写自动常量x = fn();可能更自然。如果您知道函数不返回引用,并且您希望对象x保持不变,以避免出现错误,或记录它在范围内的使用,则为已知。同样,您通常也不会这样写:const int&x = 1; 但是由于以这种方式声明的引用的生存期延长规则,auto const&确实给出了等效的结果。
Spacen Jasset

47

是的,对于局部变量使用auto和是正确的auto&。获取函数的返回类型时,使用也是正确的auto&。这也适用于基于范围的循环。

使用的一般规则auto是:

  • 选择auto x您想使用副本的时间。
  • 选择auto &x何时要使用原始项目并可以对其进行修改。
  • 选择auto const &x何时要使用原始项目,而不修改它们。

您可以在此处阅读有关自动说明符的更多信息。


9

auto使用与模板相同的类型推导机制,我知道的唯一例外是括号初始化列表,它由autoas推导std::initializer_list,但在模板上下文中未推导。

auto x = expression;

首先从右侧表达式的类型中删除所有引用和cv限定词,然后匹配该类型。举例来说,如果你有const int& f(){...}那么auto x = f();推断xint,而不是 const int&

另一种形式

auto& x = expression

不会剥离cv限定词,因此,使用上面的示例auto& x = f()推导xconst int&。其他组合仅添加cv限定词。

如果希望始终使用cv-ref限定词来推导您的类型,请使用decltype(auto)C ++ 14中的臭名昭著,它使用decltype类型推导规则。

因此,简而言之,如果要复制,请使用auto,如果要引用,请使用auto&。使用const时,你想要更多的const-ness。


编辑 还有一个用例,

auto&& x = expression;

它使用引用折叠规则,与转发模板代码中的引用的情况相同。如果expression是左值,则x是具有cv限定词的左值引用expression。如果expression为右值,x则为右值引用。


@Potatoswatter谢谢,编辑。我实际上想知道的简历rvalues。有没有简单的测试方法?以及如何获得简历合格的右值?在函数返回时,cv被丢弃。
vsoftco

不,它不会在函数返回时被丢弃。对于所有标量类型的prvalue都将其丢弃(C ++ 14 [和其他版本]§5/ 6)。您可以使用函数调用或强制转换表示法得到一个。Cv限定的xvalue的工作原理与其他任何事物相同:auto && x = std::move< const int >( 5 );将声明int const && x,尽管很少使用。
Potatoswatter

@Potatoswatter谢谢,你是对的,我的错。我首先使用POD进行了测试,在这种情况下,cv被丢弃了,并认为这是一般情况。当然,不应将其丢弃,因为通常来说,您可能希望保留cv(例如,这样一来,您就无法在rvalue返回上调用非const成员函数)。
vsoftco 2015年

丢弃标量类型。POD可能是类。无论如何,这是表达式模型和对象模型相交的一个棘手的角落。
Potatoswatter 2015年

2

创建局部变量时,使用(const)auto&或auto是否正确?

是。auto只不过是编译器推导的类型,因此在通常使用引用的地方使用引用,在通常使用本地副本的地方使用本地(自动)副本。是否使用引用与类型推导无关。

SomeMethod()返回非原始值的地方-可能是另一个用户定义的类型。我的理解是const auto&result是正确的,因为SomeMethod()返回的结果将为返回的类型调用复制构造函数。如果我错了,请纠正我。

法律?是的,使用const。最佳实践?可能不是。至少不是C ++ 11。如果从SomeMethod()返回的值已经是临时值,则尤其不能。您将要了解C ++ 11移动语义,复制省略和返回值优化:https : //juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by-值/

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=199

https://isocpp.org/wiki/faq/ctors#return-by-value-optimization

原始类型呢?我假设const auto sum = 1 + 2; 是正确的。

是的,这很好。

这是否也适用于基于范围的for循环?

for(const auto&object:对象)

是的,这也很好。我一直在工作时编写此类代码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.