std:: vecteur, construction par défaut, C++11 et changements de rupture
j'ai couru aujourd'hui contre une assez subtile question j'aimerais avoir votre avis sur.
considérer la variété de jardin suivante corps partagé-classe idiome:
struct S
{
S() : p_impl(new impl) {}
private:
struct impl;
boost::shared_ptr<impl> p_impl;
};
Le plaisir s'affiche lorsque vous essayez de les mettre dans des vecteurs de la manière suivante:
std::vector<S> v(42);
maintenant, avec MSVC 8 au moins, tous les éléments dans v
partagent le même impl
membre. En fait ,ce qui cause ceci est le vector
constructeur:
template <typename T, typename A = ...>
class vector
{
vector(size_t n, const T& x = T(), const A& a = A());
...
};
sous les scènes, un seul objet S
est construit par défaut, les éléments n
du vector
en sont copiés.
maintenant, avec C++11, Il y a des références de valeur. Donc il ne peut pas travailler comme ça. Si un vector
est construit comme
std::vector<S> v(42);
alors très probablement, les implémentations choisiront de construire par défaut les objets n
à l'intérieur du vecteur, puisque la copie peut ne pas être disponible. Ce serait un changement décisif dans ce cas.
ma question Est:
- le C++03 standard mandats que
std::vector
doit posséder un constructeur définis comme ci-dessus, c'est à dire. avec un argument par défaut ? En particulier est-il une garantie que les entrées de l'objet vectoriel d'avoir copié à la place de défaut construit ? - que dit la norme C++11 à propos de ce même point ?
- je vois cela comme une possibilité pour un changement de rupture entre C++03 et C+11. Ce problème étudié ? Résolu ?
PS: Svp pas de commentaires sur le constructeur par défaut de la classe S
ci-dessus. C'était ça ou mettre en place une forme de construction paresseuse.
2 réponses
le C++03 standard mandat que
std::vector
doit posséder un constructeur définis comme ci-dessus, c'est à dire avec un argument par défaut? En particulier est-il une garantie que les entrées de l'objet vectoriel d'avoir copié à la place de défaut construit?
Oui, le comportement spécifié est que x
est copié n
temps de sorte que le conteneur est initialisé à contenir avec n
des éléments qui sont toutes des copies de x
.
que dit la norme C++11 sur ce même point?
en C++11 ce constructeur a été transformé en deux constructeurs.
vector(size_type n, const T& x, const Allocator& = Allocator()); // (1)
explicit vector(size_type n); // (2)
sauf qu'il n'a plus d'argument par défaut pour le second paramètre, (1) fonctionne de la même manière qu'en C++03: x
est copié n
temps.
au lieu de l'argument par défaut pour x
, (2) a été ajouté. Ce constructeur valeur-initialise n
éléments dans le conteneur. Pas de copies sont faites.
si vous avez besoin de l'ancien comportement, vous pouvez vous assurer que (1) est appelé en fournissant un second argument à l'invocation du constructeur:
std::vector<S> v(42, S());
je vois cela comme une possibilité pour un changement de rupture entre C++03 et C++11. Je vois cela comme une possibilité de rupture entre C++03 et C++11. Ce problème étudié? Résolu?
Oui, comme votre exemple le démontre, il s'agit en effet d'un changement décisif.
comme je ne suis pas membre du comité de standardisation C++ (et je n'ai pas porté une attention particulière aux documents relatifs aux bibliothèques dans le mailings), Je ne sais pas dans quelle mesure ce changement radical a été discuté.
je pense que la solution pour le cas d'utilisation que vous avez décrit n'est pas optimale et pas complète, c'est pourquoi vous avez des problèmes de mise à niveau vers C++11.
C++ se soucie toujours de sémantique et quand vous écrivez un programme en c++ vous devriez mieux comprendre votre sémantique. Donc dans votre cas vous souhaitez créer des N objets, mais si vous n'êtes pas les changer vous les voulez partagent la même mémoire pour l'optimisation. Bonne idée, mais comment obtenir ce fait: 1) le constructeur de copie. 2) implémentation statique + copie constructeur. Avez-vous envisagé les deux solutions?
Considérez-vous besoin de M vecteurs de N objets, combien de fois la mémoire partagée sera attribué si vous choisissez le 1er scénario? C'est M, mais pourquoi devons-nous allouer des temps m de mémoire si nous voulons créer des vecteurs contenant des objets MxN?
donc l'implémentation correcte ici est de pointer vers la mémoire statique par défaut, et allouer la mémoire uniquement si l'objet est modifié. Dans ce cas, attribuer des vecteurs M de n objets vais vous donner... 1 allocation de mémoire "partagée".
Dans votre cas, vous avez violé corriger sémantique abuser de constructeur de copie, qui est: 1) pas évident 2) pas optimal et maintenant tu dois payer.