В чем разница между типами bar1 и bar2?

int foo = 10;
auto bar1 = &foo;
auto *bar2 = &foo;

Что случилось до сих пор

56
Henry Barker 2 Янв 2016 в 00:45

6 ответов

Лучший ответ

Заявления полностью эквивалентны. auto работает (почти) так же, как определение типа шаблона. Явное указание звездочки делает код немного более читаемым и дает программисту понять, что bar2 является указателем.

54
vsoftco 1 Янв 2016 в 21:57

Это не имеет значения, поскольку идет интерпретация кода C ++; ты можешь писать все, что хочешь. Однако возникает вопрос стиля и удобочитаемости: как правило, вам не следует скрывать указатели, ссылки и квалификаторы CV и, возможно, даже интеллектуальные указатели в псевдонимах типов, поскольку читателю сложнее понять, что происходит. Псевдонимы типа должны упаковывать семантически релевантное содержимое типа, тогда как квалификаторы и модификаторы должны оставаться видимыми. Так что предпочитаю следующее:

 using Foo = long_namespace::Foobrigation<other_namespace::Thing>;
 using MyFn = const X * (int, int);

 std::unique_ptr<Foo> MakeThatThing(MyFn & fn, int x)   // or "MyFn * fn"
 { 
     const auto * p = fn(x, -x);
     return p ? p->Create() : nullptr;
 }

И не говори:

using PFoo = std::unique_ptr<Foo>;   // just spell it out
using MyFn = int(&)(int, int);       // unnecessary; & is easy to spell
auto p = fn(x, -x);                  // Don't know that p is a pointer

Также обратите внимание, что ссылочные квалификаторы (в отличие от указателей) действительно изменяют тип объявляемой переменной, поэтому они не являются необязательными:

X & f();
auto a = f();    // copy!
auto & b = f();  // b is the same as the return value of f()

Наконец, добавление явных квалификаций константного указателя может помочь константной корректности. Рассмотрим следующий пример, в котором контейнер содержит изменяемые указатели, но нам нужен только константный доступ. Просто auto * выведет указатель на изменяемый объект, чего мы можем избежать, явно указав const:

std::vector<X*> v = /* ... */;
for (const auto * p : v)
{
    observe(p->foo());   // no need for a mutable *p
}
8
Kerrek SB 1 Янв 2016 в 22:29

Как говорили другие, они будут генерировать один и тот же код. Звездочка - это шум строки (и затрудняет переключение с необработанных указателей на интеллектуальные указатели, если, например, &foo когда-либо заменяется на get_foo()). Если вы хотите быть явным, то во что бы то ни стало; но когда вы используете вывод типа, просто позвольте компилятору делать свою работу. Отсутствие звездочек не означает, что объект не является указателем.

10
Jeff Schwab 4 Янв 2016 в 16:56

Использование auto * "намерение документов". И auto *p = expr; может быть выведен правильно, только если expr возвращает указатель. Пример:

int f();

auto q = f(); // OK

auto *p = f(); // error: unable to deduce 'auto*' from 'f()'
56
Victor Dyachenko 2 Янв 2016 в 16:58

В этом конкретном примере и bar1, и bar2 одинаковы. Это вопрос личных предпочтений, хотя я бы сказал, что bar2 легче читать.

Однако это не относится к ссылкам, показанным в этом примере:

#include <iostream>
using namespace std;

int main() {
    int k = 10;
    int& foo = k;
    auto bar = foo; //value of foo is copied and loses reference qualifier!
    bar = 5; //foo / k won't be 5
    cout << "bar : " << bar << " foo : " << foo << " k : " << k << endl;
    auto& ref = foo;
    ref = 5; // foo / k will be 5
    cout << "bar : " << bar << " foo : " << foo << " k : " << k;
    return 0;
}
14
Hatted Rooster 1 Янв 2016 в 21:55

Когда вы используете квалификаторы const, есть большая разница:

int i;

// Const pointer to non-const int
const auto ip1 = &i; // int *const
++ip1; // error
*ip1 = 1; // OK

// Non-const pointer to const int
const auto* ip2 = &i; // int const*
++ip2; // OK
*ip2 = 1; // error
18
danpla 29 Ноя 2016 в 13:53