web-dev-qa-db-fra.com

Déclaration automatique C ++ 11 avec et sans déclarateur de pointeur

Quelle est la différence entre les types de bar1 et bar2?

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

Si les deux bar1 et bar2 sont int*, est-il logique d'écrire le déclarant du pointeur (*) dans le bar2 déclaration?

50
Henry Barker

Les déclarations sont exactement équivalentes. auto fonctionne (presque) de la même manière que déduction du type de modèle . Mettre l'étoile explicitement rend le code un peu plus facile à lire et rend le programmeur conscient que bar2 est un pointeur.

47
vsoftco

En utilisant auto * "documents intention". Et auto *p = expr; ne peut être déduit correctement que si expr renvoie un pointeur. Exemple:

int f();

auto q = f(); // OK

auto *p = f(); // error: unable to deduce 'auto*' from 'f()'
51
Victor Dyachenko

Il y a une grande différence lorsque vous utilisez les qualificatifs 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
14
danpla

Dans cet exemple spécifique, les deux bar1 et bar2 sont identiques. C'est une question de préférence personnelle, mais je dirais que bar2 est plus facile à lire.

Cependant, cela ne vaut pas pour les références comme vu dans ce exemple :

#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
Sombrero Chicken

Comme d'autres l'ont dit, ils généreront le même code. L'astérisque est le bruit de ligne (et rend plus difficile le passage des pointeurs bruts aux pointeurs intelligents si, par exemple, &foo Est jamais remplacé par get_foo()). Si vous voulez être explicite, alors certainement, soyez explicite; mais lorsque vous utilisez l'inférence de type, laissez simplement le compilateur faire son travail. Le manque d'astérisques n'implique pas qu'un objet n'est pas un pointeur.

10
Jeff Schwab

Peu importe l'interprétation du code C++; vous pouvez écrire ce que vous voulez. Cependant, il y a une question de style et de lisibilité: en général, vous ne devez pas masquer les qualificateurs de pointeur, de référence et de CV, et peut-être même des pointeurs intelligents, dans les alias de type, car cela rend plus difficile pour le lecteur de comprendre que c'est ce qui se passe. Les alias de type doivent regrouper le contenu de type sémantiquement pertinent, tandis que les qualificateurs et les modificateurs doivent rester visibles. Alors préférez ce qui suit:

 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;
 }

Et ne dites pas:

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

Notez également que les qualificatifs de référence (contrairement aux pointeurs) modifient véritablement le type de la variable qui est déclarée, ils ne sont donc pas facultatifs:

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

Enfin, l'ajout de qualifications explicites de pointeur const peut aider à l'exactitude de const. Prenons l'exemple suivant, dans lequel un conteneur contient des pointeurs vers mutable, mais nous n'avons besoin que d'un accès const. Juste auto * déduirait un pointeur sur mutable, ce que nous pouvons éviter en disant explicitement const:

std::vector<X*> v = /* ... */;
for (const auto * p : v)
{
    observe(p->foo());   // no need for a mutable *p
}
7
Kerrek SB