43 votes

Pourquoi C ++ 11 a-t-il supprimé la valeur par défaut des prototypes du constructeur de remplissage de std :: vector?

En C++98 le prototype std::vectors'remplir constructeur a une valeur par défaut pour l'initialiseur.

explicit vector (size_type n, const value_type& val = value_type(),
                 const allocator_type& alloc = allocator_type());

C++11 utilise deux prototypes.

explicit vector (size_type n);
         vector (size_type n, const value_type& val,
                 const allocator_type& alloc = allocator_type());

(En C++14 le remplissage constructeur de nouveau changé, mais ce n'est pas le point de cette question.)

Un lien de référence est ici.

Pourquoi C++11 déprécier la valeur par défaut de l'initialiseur valeur value_type()?

En passant, j'ai essayé de compiler le code suivant avec clang++ -std=c++11 et il a publié une erreur, ce qui signifie que le type de la valeur doit encore avoir un constructeur par défaut comme S() {}, c'està-dire par défaut constructible.

#include <vector>

struct S {
    int k;
    S(int k) : k(k) {} // intentionally remove the synthesized default constructor
};

int main() {
    std::vector<S> s(5); // error: no matching constructor
}

51voto

Yakk Points 31636

Le C++98 a pris un prototype de l'objet, puis copié n fois. Par défaut, le prototype a été un défaut-objet construit.

Le C++11 version constructions n valeur par défaut-objets construits.

Ceci élimine n copies et le remplace par n par défaut-constructions. En outre, il évite la construction du prototype.

Supposons que votre classe ressemble à ceci:

struct bulky {
  std::vector<int> v;
  bulky():v(1000) {} // 1000 ints
  bulky(bulky const&)=default;
  bulky& operator=(bulky const&)=default;

  // in C++11, avoid ever having an empty vector to maintain
  // invariants:
  bulky(bulky&& o):bulky() {
    std::swap(v, o.v);
  }
  bulky& operator=(bulky&& o) {
    std::swap(v,o.v);
    return *this;
  }
};

c'est une classe qui toujours est propriétaire d'un tampon d' 1000 ints.

si nous créons alors un vecteur d' bulky:

std::vector<bulky> v(2);

en C++98 cette alloué 3 fois 1000 entiers. En C++11 ce alloué à seulement 2 fois 1000 entiers.

De plus, le C++98 version exige que le type de l'être copiable. Il y a des non-copiable types en C++11, comme std::unique_ptr<T>, et un vector de la valeur par défaut-construit unique pointeurs ne peut pas être généré en utilisant le C++98 signature. Le C++11 signature n'a pas de problème avec elle.

std::vector<std::unique_ptr<int>> v(100);

Le ci-dessus ne fonctionnent pas si on avait encore le C++version 98.

47voto

Howard Hinnant Points 59526

La raison pour laquelle le constructeur a été divisé en deux était à l'appui de "déplacer" uniquement " les types comme unique_ptr<T>.

Ce constructeur:

vector(size_type n, const T& value, const Allocator& = Allocator());

exige T pour être la copie constructible, car n Ts doit être copié à partir d' value pour remplir l' vector.

Ce constructeur:

explicit vector(size_type n, const Allocator& = Allocator());

ne pas exiger T pour être la copie constructible, seul défaut constructible.

Le dernier constructeur travaille avec unique_ptr<T>:

std::vector<std::unique_ptr<int>> s(5);

alors que le premier constructeur ne le fait pas.

Voici la proposition que fait ce changement: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1858.html#23.2.4.1%20-%20vector%20constructors,%20copy,%20and%20assignment

Et ce papier a un peu de la justification, mais certes un peu sur le côté laconique: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html

Fwiw, resize:

void resize(size_type sz, T c = T());

a été divisé en:

void resize(size_type sz);
void resize(size_type sz, const T& c);

pour exactement la même raison. La première exige par défaut constructible mais pas de copier constructibles (à l'appui de défaut constructible déplacer uniquement les types), et la seconde nécessite copie constructible.

Ces changements ne sont pas 100% compatibles. Pour certains types (par exemple, un décompte de références pointeurs intelligents), copie de la construction d'un défaut objet construit est pas le même que le défaut de construction. Toutefois, le bénéfice de l'appui déplacer uniquement les types a été jugé être vaut le coût de cette API rupture.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X