【问题标题】:Is there any reason to use the 'auto' keyword in C++03?是否有任何理由在 C++03 中使用“auto”关键字?
【发布时间】:2010-11-05 23:57:21
【问题描述】:

注意这个问题最初发布于 2009 年,在 C++11 被批准之前,auto 关键字的含义发生了巨大变化。提供的答案auto 的C++03 含义有关——即指定的存储类——而不是auto 的C++11 含义——即自动类型扣除。如果您正在寻找有关何时使用 C++11 auto 的建议,此问题与该问题无关。

很长一段时间以来,我认为没有理由在 C 中使用 static 关键字,因为在块范围之外声明的变量是隐式全局的。然后我发现在块范围内将变量声明为static 会赋予它永久的持续时间,而在块范围之外(在程序范围内)声明它会给它文件范围(只能在该编译单元中访问) )。

所以这给我留下了一个我(也许)还没有完全理解的关键字:auto 关键字。除了“局部变量”之外,它还有其他含义吗?无论您想在哪里使用它,它所做的任何事情都没有为您隐含地完成? auto 变量在程序范围内的行为如何?文件范围内的static auto 变量是什么?除了为了完整性而存在之外,这个关键字还有其他用途吗?

【问题讨论】:

    标签: c++ keyword c++03


    【解决方案1】:

    在 C++11 中,auto 有了新的含义:它允许你自动推断变量的类型。

    为什么这很有用?让我们考虑一个基本的例子:

    std::list<int> a;
    // fill in a
    for (auto it = a.begin(); it != a.end(); ++it) {
      // Do stuff here
    }
    

    那里的auto 创建了一个std::list&lt;int&gt;::iterator 类型的迭代器。

    这可以使一些非常复杂的代码更容易阅读。

    另一个例子:

    int x, y;
    auto f = [&]{ x += y; };
    f();
    f();
    

    在那里,auto 推断出将 lambda 表达式存储在变量中所需的类型。 维基百科有好的coverage on the subject.

    【讨论】:

    • 仍然不确定这是否很好地使用了 auto。代码应该易于阅读,而不是易于编写!
    • 我不知道你的情况,但我发现这比迭代器类型的垃圾邮件更容易阅读。
    • 如果出于某种原因 zou 决定将类从 list 更改为其他类,您不必搜索每个迭代器声明并进行更改。
    • @KarateSnowMachine:如果你想要 const,你可以使用“const auto”而不是“auto”。
    • @darth const auto it = a.begin(); 会给你一个常量iterator,而不是const_iterator。您仍然应该更改元素,但 ++it 将无法编译。要获得const_iterator,您可以使用auto it = a.cbegin();
    【解决方案2】:

    auto 是存储类说明符,staticregisterextern 也是。您只能在声明中使用这四种中的一种。

    局部变量(没有static)具有自动存储持续时间,这意味着它们从定义开始到块结束都存在。将 auto 放在它们前面是多余的,因为无论如何这是默认设置。

    我不知道有什么理由在 C++ 中使用它。在具有隐式 int 规则的旧 C 版本中,您可以使用它来声明变量,例如:

    int main(void) { auto i = 1; }
    

    如果i 在范围内,使其语法有效或与赋值表达式消除歧义。但这无论如何在 C++ 中都不起作用(你必须指定一个类型)。有趣的是,C++ 标准写道:

    在块范围内声明没有存储类说明符或声明为函数参数的对象默认具有自动存储持续时间。 [注意:因此, auto 说明符几乎总是多余的并且不经常使用; auto 的一种用途是明确区分声明语句和表达式语句(6.8)。 ——尾注]

    它指的是以下场景,可以是aint 的强制转换,也可以是int 类型的变量a 的声明,在a 周围有多余的括号。它总是被认为是一个声明,所以auto 不会在这里添加任何有用的东西,而是会为人类添加。但是话又说回来,人类最好删除a周围的多余括号,我会说:

    int(a);
    

    随着 auto 的新含义与 C++0x 一起出现,我不鼓励在代码中将其与 C++03 的含义一起使用。

    【讨论】:

    • C++ 编译器通常使用隐式 int 来表示函数的返回值,早在标准之前的 ARM 时代......在 EMPIRE 之前......
    • 我刚刚意识到这是我的编译器告诉我我忘记前向声明函数的方式。它会告诉我,由于隐式 int,我对函数的使用与声明它的方式不同。
    • 最好的部分是程序员过去常常写“auto”(四个字母)来避免写“int”(三个字母)。
    • @Max - 嘿,很多人说“double-u-double-u-double-u”是“万维网”的缩写。
    • @smichak 不,“volatile”是一个类型限定符。它不是确定存储值的位置,而是更改对 volatile 限定类型对象的写入和读取行为。可以有 volatile 限定的堆栈变量(自动存储类)以及 volatile 限定的静态存储持续时间变量(本地“静态”存储类、非本地变量)。除此之外,我不知道“寄存器易失性”是否是一个有效的组合:)
    【解决方案3】:

    auto 关键字目前没有任何用途。你说得对,它只是重述了局部变量的默认存储类,真正有用的替代方案是static

    它在 C++0x 中有一个 brand new meaning。这让你知道它是多么无用!

    【讨论】:

    • 哦,伙计,那永远没用。不过我喜欢新的含义。它使一些代码不那么冗长和冗余。
    • 是的,在 C# 中使用了等价物可能会产生巨大的影响。在 C++ 中更是如此,如果您使用的表达式模板的类型非常复杂,以至于它们从未打算手动写出。
    【解决方案4】:

    GCC 对嵌套函数有一个特殊的使用 auto - 请参阅 here

    如果你有嵌套函数要在定义之前调用,你需要用auto声明它。

    【讨论】:

    • 这是一个很棒的 auto 实现,尽管它依赖于编译器。感谢您的研究:)
    【解决方案5】:

    “auto”应该告诉编译器自己决定将变量(内存或寄存器)放在哪里。它的模拟是“寄存器”,据说它告诉编译器尝试将它保存在寄存器中。现代编译器忽略了两者,所以你也应该这样做。

    【讨论】:

    • 不完全是——如果你用“register”声明它,编译器不允许你在变量上使用地址运算符(&foo),因为它不存在于内存中的任何地方(因此没有地址)。
    【解决方案6】:

    对于基于堆栈的处理器,我使用此关键字明确记录何时将变量放置在堆栈上对函数至关重要。在从函数(或中断服务程序)返回之前修改堆栈时,可能需要此函数。 在这种情况下,我声明:

    auto unsigned int auiStack[1];   //variable must be on stack
    

    然后我访问变量外部:

    #define OFFSET_TO_RETURN_ADDRESS 8     //depends on compiler operation and current automatics
    auiStack[OFFSET_TO_RETURN_ADDRESS] = alternate_return_address;
    

    所以auto 关键字有助于记录意图。

    【讨论】:

    • 我认为这只是信号意图,因为关键字实际上并不强制堆栈放置,而不是简单地省略它。
    【解决方案7】:

    根据 Stroustrup 的说法,在“The C Programming Language”(第 4 版,涵盖 C 11)中,使用 'auto' 有以下主要原因(第 2.2.2 节)(引用 Stroustrup 的话):

    1)

    该定义在我们想要制作类型的大范围内 对我们代码的读者来说清晰可见。

    使用 'auto' 及其必要的初始化器,我们可以一眼就知道变量的类型!

    2)

    我们希望明确变量的范围或精度(例如,双精度而不是浮点)

    在我看来,适合这里的情况是这样的:

       double square(double d)
        {
            return d*d; 
        }
    
        int square(int d)
        {
            return d*d; 
        }
    
        auto a1 = square(3);
    
        cout << a1 << endl;
    
        a1 = square(3.3);
    
        cout << a1 << endl;
    

    3)

    使用 'auto' 我们避免了冗余和编写长类型名称。

    想象一下来自模板化迭代器的一些长类型名称:

    (来自第 6.3.6.1 节的代码)

    template<class T> void f1(vector<T>& arg) {
        for (typename vector<T>::iterator p = arg.begin(); p != arg.end();   p)
            *p = 7;
    
        for (auto p = arg.begin(); p != arg.end();   p)
            *p = 7;
    }
    

    【讨论】:

    • 这些点适用于 C++11,但不适用于 C++03。类型推断是 C++11 中的新功能。
    【解决方案8】:

    在旧的编译器中,auto 是一种声明局部变量的方法。在没有 auto 关键字或类似关键字的情况下,您无法在 Turbo C 等旧编译器中声明局部变量。

    【讨论】:

    • 恐怕你弄错了。即使在 1986 年 Turbo C 的原始版本 Wizard-C 或其同时代的任何版本中,也从未有过这样的限制:MSC、Lattice C、Concurrent-C、High-C、Watcom-C...
    【解决方案9】:

    Microsoft 的 Stephan T. Lavavej 在 MSDN 的 Channel 9 站点 here 上可免费查看/下载的 STL 视频讲座中很好地描述了 C++0x 中 auto 关键字的新含义。

    讲座值得完整观看,但关于 auto 关键字的部分大约在第 29 分钟(大约)。

    【讨论】:

      【解决方案10】:

      “auto”除了“局部变量”还有其他含义吗?

      不在 C++03 中。

      它所做的任何事情都没有隐含地为你完成,无论你想在哪里使用它?

      什么都没有,在 C++03 中。

      自动变量在程序范围内的行为如何?文件范围内的静态自动变量是什么?

      关键字不允许在函数/方法体之外。

      除了为了完整性而存在之外,这个关键字[在 C++03 中] 是否还有其他用途?

      令人惊讶的是,是的。 C++ 设计标准包括与 C 的高度向后兼容性。C 有这个关键字,没有真正的理由禁止它或重新定义它在 C++ 中的含义。因此,目的是减少与 C 的不兼容。

      除了为了完整性而存在之外,这个关键字在 C 中还有其他用途吗?

      我最近才知道:从 B 中轻松移植古代程序。C 是从一种称为 B 的语言演变而来的,它的语法与 C 的语法非常相似。但是,B 没有任何类型。在 B 中声明变量的唯一方法是指定其存储类型(autoextern)。像这样:

      自动我;

      此语法在 C 中仍然有效,等效于

      int i;

      因为在 C 中,存储类默认为auto,类型默认为int。我猜当时每个源自 B 并移植到 C 的程序实际上都充满了auto 变量。

      C++03 不再允许 C 风格的隐式 int,但它保留了不再完全有用的 auto 关键字,因为与隐式 int 不同,它不会在C.

      【讨论】:

        猜你喜欢
        • 2011-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-23
        • 2014-03-08
        • 2018-10-20
        • 1970-01-01
        相关资源
        最近更新 更多