Чи є якась причина використовувати ключове слово 'auto' у C ++ 03?


85

Зауважте, це питання було спочатку опубліковано у 2009 році, до того, як було затверджено C ++ 11 і до того, як значення autoключового слова було кардинально змінено. Надані відповіді стосуються лише значення C ++ 03 auto- що є вказаним класом зберігання - а не значення C ++ 11 auto- що є автоматичним вирахуванням типу. Якщо ви шукаєте пораду щодо того, коли використовувати C ++ 11 auto, це питання не стосується цього питання.

Найдовше я думав, що немає жодної причини використовувати staticключове слово в C, оскільки змінні, оголошені поза сферою блоку, були неявно глобальними. Потім я виявив, що оголошення змінної як staticусередині блоку-сфери дасть їй постійну тривалість, а оголошення за межами області блоку (у програмі-області) дасть їй область області (доступ до неї можна отримати лише в цьому модулі компіляції).

Отже, у мене залишається лише одне ключове слово, яке я (можливо) ще не повністю розумію: autoКлючове слово. Чи є в цьому якесь інше значення, крім "локальна змінна?" Що-небудь, що він робить, не виконується неявно для вас, де б ви не хотіли це використовувати? Як поводиться autoзмінна в обсязі програми? Що з static autoзмінною у діапазоні файлів? Чи має це ключове слово якісь цілі, крім лише існуючих, для повноти ?

Відповіді:


74

autoє специфікатором класу сховища static, registerі externтеж. Ви можете використовувати лише один із цих чотирьох у декларації.

Локальні змінні (без static) мають автоматичну тривалість зберігання, що означає, що вони живуть від початку їх визначення до кінця їх блоку. Постановка авто перед ними зайва, оскільки це так чи інакше за замовчуванням.

Я не знаю жодної причини використовувати його в C ++. У старих версіях C, які мають неявне правило int, ви можете використовувати його для оголошення змінної, як у:

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

Зробити його дійсним синтаксисом або визначити незрозумілість із виразом присвоєння у випадку, якщо iце в області дії. Але це все одно не працює в C ++ (потрібно вказати тип). Досить смішно, C ++ Standard пише:

Об'єкт, оголошений без специфікатора класу сховища в області блоку або оголошений як параметр функції, за замовчуванням має автоматичну тривалість зберігання. [Примітка: отже, автоматичний специфікатор майже завжди надлишковий і не часто використовується; одне з використання auto - це явне розрізнення декларації-висловлення від виразу-висловлювання (6.8). - кінцева примітка]

що посилається на наступний сценарій, який може бути або приведенням aдо intабо оголошенням змінної aтипу, що intмає надлишкові дужки навколо a. Це завжди приймається як декларація, тому autoне додав би тут нічого корисного, а натомість для людини. Але знову ж таки, людині було б краще видалити зайві дужки навколо a, я б сказав:

int(a);

З новим значенням autoнадходження з C ++ 0x, я б не рекомендував використовувати його зі значенням C ++ 03 у коді.


4
Компілятори C ++ часто використовували неявний int для повернення значень із функцій, ще за ARM днів до стандарту ... До EMPIRE ...
Daniel Earwicker

1
Я просто розпізнав це як спосіб компіляторів, який сказав мені, що забув переадресувати декларацію функції. Це сказало б мені, що моє використання функції відрізнялося від того, як було оголошено через неявний int.
Карсон Майерс,

29
Найкраще те, що програмісти писали "auto" (чотири літери), щоб уберегти себе від написання "int" (три літери).
Макс Лібберт,

30
@Max - привіт, багато людей кажуть "double-u-double-u-double-u" як абревіатуру від "Всесвітня павутина".
Даніель Ервікер

3
@smichak ні, "volatile" - це кваліфікатор типу. Замість того, щоб визначати, де зберігати значення, він змінює поведінку запису та читання з об’єкта летючого кваліфікованого типу. Можуть бути мінливі кваліфіковані змінні стека (клас автоматичного зберігання), а також мінливі кваліфіковані статичні змінні тривалості зберігання (локальний 'статичний' клас зберігання, нелокальні змінні). Окрім цього, я не знаю, чи "реєстрація нестабільних" є допустимою комбінацією :)
Йоганнес Шауб - літ

86

У 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<int>::iterator.

Це може значно спростити читання деяких серйозно складних кодів.

Інший приклад:

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

Там autoвиведений тип, необхідний для зберігання лямбда-виразу у змінній. Вікіпедія добре висвітлює цю тему.


4
Досі не впевнений, чи це чудове використання авто. Код повинен бути легким для читання, а не простим для написання!
ДанДан

38
Я не знаю про вас, але мені це легше читати, ніж спам типу ітератора.
Оверв

17
І якщо для якогось резонансу ви вирішите змінити клас зі списку <int> на інший клас, вам не доведеться шукати кожну декларацію ітератора та змінювати його.
roslav

2
@KarateSnowMachine: Якби ви хотіли const, ви б використовували "const auto" замість "auto".
darth happyface

4
@darth const auto it = a.begin();дасть вам const iterator, а не a const_iterator. Ви все одно можете змінити елемент, але ++itне зможете скомпілювати. Щоб отримати const_iterator, ви скористаєтесьauto it = a.cbegin();
fredoverflow

35

Ключове слово auto на даний момент не має призначення. Ви абсолютно праві, що він просто повторює клас зберігання за замовчуванням локальної змінної, справді корисною альтернативою static.

Це має абсолютно нове значення в C ++ 0x. Це дає вам деяке уявлення про те, наскільки це було марно!


1
о, людино, це коли-небудь марно. Мені все ж подобається нове значення. Це робить деякий код набагато менш багатослівним і зайвим.
Карсон Майєрс

Так, якщо використовувати еквівалент у C #, це, мабуть, матиме величезну різницю. Тим більше в C ++, якщо ви використовуєте шаблони виразів, де типи настільки складні, що їх ніколи не передбачалося виписувати вручну.
Даніель Ервікер

7

GCC спеціально використовує autoдля вкладених функцій - див. Тут .

Якщо у вас є вкладена функція, яку ви хочете викликати до її визначення, вам потрібно оголосити її за допомогою auto.


це чудова, хоч і залежна від компілятора, реалізація auto. Дякую за дослідження :)
Карсон Майєрс,

3

"auto" нібито повідомляє компілятору самостійно вирішити, куди помістити змінну (пам'ять або регістр). Його аналогом є "регістр", який нібито говорить компілятору намагатися зберегти його в реєстрі. Сучасні компілятори ігнорують обидва, тому вам теж слід.


1
Не зовсім так - якщо ви оголосите це за допомогою "register", компілятори не дозволять вам використовувати оператор адреса (& foo) для змінної, оскільки, ну, він ніде не існує в пам'яті (і, отже, не має адреси).
Tim Čas

3

Я використовую це ключове слово для явного документування, коли для функції критично важливо, щоб змінна була розміщена в стеці для процесорів на основі стеку. Ця функція може знадобитися під час модифікації стека перед поверненням із функції (або підпрограми обслуговування переривання). У цьому випадку я заявляю:

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ключове слово допомагає задокументувати намір.


Я припускаю, що це лише сигналізація про намір, оскільки ключове слово насправді не примушує розміщувати стек, а не просто пропускаючи це.
underscore_d

2

За словами Строуструпа, у "Мові програмування С" (4-е видання, що охоплює С 11), використання "авто" має такі основні причини (розділ 2.2.2) (цитуються слова Страуструпа):

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)

Використовуючи "авто", ми уникаємо надмірності та написання довгих імен типів.

Уявіть собі довге ім’я типу із шаблонізованого ітератора:

(код із розділу 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;
}

1

У старому компіляторі auto взагалі був одним із способів оголосити локальну змінну. Ви не можете оголосити локальні змінні у старих компіляторах, таких як Turbo C, без ключового слова auto або якогось іншого.


1

Новий сенс автоматичного ключового слова в C ++ 0x описується дуже красиво по Microsoft, Стефан Т. Lavavej в вільно видиму / завантажувати відео лекції з STL знайшов на Channel 9 сайту MSDN в тут .

Лекцію варто переглянути повністю, але частина про ключове слово auto знаходиться приблизно на позначці 29-ї хвилини (приблизно).


0

Чи є якесь інше значення для "авто", крім "локальна змінна?"

Не в C ++ 03.

Що-небудь, що він робить, не виконується неявно для вас, де б ви не хотіли це використовувати?

Нічого взагалі, в C ++ 03.

Як поводиться автоматична змінна в області програми? Що з статичною автоматичною змінною у діапазоні файлів?

Ключове слово не допускається поза тілом функції / методу.

Чи має це ключове слово будь-яке призначення [в C ++ 03], крім просто існуючого для повноти?

Дивно, але так. Критерії проектування C ++ включали високий ступінь зворотної сумісності з C. C мав це ключове слово, і не було жодної реальної причини заборонити його або перевизначити його значення в C ++. Отже, метою була одна несумісність із C.

Чи має це ключове слово будь-яке призначення на мові C, крім просто існуючого для повноти?

Я дізнався про це зовсім недавно: простота перенесення давніх програм з B. C розвинулася з мови під назвою B, синтаксис якої був досить схожий на синтаксис C. Однак B не мав жодних типів. Єдиним способом оголосити змінну в B було вказати її тип зберігання ( autoабо extern). Подобається це:

авто i;

Цей синтаксис все ще працює на C і еквівалентний

int i;

тому що в C клас зберігання за замовчуванням autoі тип за замовчуванням int. Я припускаю, що кожна окрема програма, яка виникла у мові B та була перенесена на мову C, буквально була переповненою autoзмінними на той час.

C ++ 03 більше не допускає неявного int-стилю C, але в ньому зберігається не зовсім корисне autoключове слово, оскільки, на відміну від неявного int, не було відомо, що він спричиняє проблеми в синтаксисі C.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.