Si je passe le code suivant via mon instantané GCC 4.7, il essaie de copier le unique_ptr
s dans le vecteur.
#include <vector>
#include <memory>
int main() {
using move_only = std::unique_ptr<int>;
std::vector<move_only> v { move_only(), move_only(), move_only() };
}
Évidemment, cela ne peut pas fonctionner car il std::unique_ptr
n'est pas copiable:
erreur: utilisation de la fonction supprimée 'std :: unique_ptr <_Tp, _Dp> :: unique_ptr (const std :: unique_ptr <_Tp, _Dp> &) [with _Tp = int; _Dp = std :: default_delete; std :: unique_ptr <_Tp, _Dp> = std :: unique_ptr] '
GCC a-t-il raison d'essayer de copier les pointeurs de la liste d'initialisation?
c++
c++11
initializer-list
move-semantics
R. Martinho Fernandes
la source
la source
Réponses:
Le synopsis de la version
<initializer_list>
18.9 indique assez clairement que les éléments d'une liste d'initialisation sont toujours passés via const-reference. Malheureusement, il ne semble pas y avoir de moyen d'utiliser move-semantic dans les éléments de la liste d'initialisation dans la révision actuelle du langage.Plus précisément, nous avons:
la source
const
, qui ne peuvent pas être rejetés dans un programme bien formé.Edit: Puisque @Johannes ne semble pas vouloir publier la meilleure solution comme réponse, je vais le faire.
Les itérateurs renvoyés par
std::make_move_iterator
déplaceront l'élément pointé lors du déréférencement.Réponse originale: nous allons utiliser un petit type d'aide ici:
Malheureusement, le code simple ici ne fonctionnera pas:
Puisque la norme, pour une raison quelconque, ne définit pas un constructeur de copie de conversion comme celui-ci:
Le
initializer_list<rref_wrapper<move_only>>
créé par l'accolade-init-list ({...}
) ne sera pas converti en celuiinitializer_list<move_only>
quevector<move_only>
prend. Nous avons donc besoin d'une initialisation en deux étapes ici:la source
std::ref
, non? Peut-être qu'il devrait être appeléstd::rref
.move_only m[] = { move_only(), move_only(), move_only() }; std::vector<move_only> v(std::make_move_iterator(m), std::make_move_iterator(m + 3));
.move_iterator
.std::distance
pour les itérateurs avant ou supérieur etstd::move_iterator
adapte la catégorie de l'itérateur sous-jacent. Quoi qu'il en soit, solution bonne et concise. Postez-le comme réponse, peut-être?Comme mentionné dans d'autres réponses, le comportement de
std::initializer_list
est de tenir les objets par valeur et de ne pas permettre de sortir, ce n'est donc pas possible. Voici une solution de contournement possible, en utilisant un appel de fonction où les initialiseurs sont donnés sous forme d'arguments variadiques:Malheureusement, il
multi_emplace(foos, {});
échoue car il ne peut pas déduire le type de{}
, donc pour que les objets soient construits par défaut, vous devez répéter le nom de la classe. (ou utiliservector::resize
)la source
En utilisant l'astuce de Johannes Schaub
std::make_move_iterator()
avecstd::experimental::make_array()
, vous pouvez utiliser une fonction d'assistance:Regardez-le en direct Coliru.
Peut-être que quelqu'un peut tirer parti de
std::make_array()
la supercherie pour lui permettremake_vector()
de faire son travail directement, mais je n'ai pas vu comment (plus précisément, j'ai essayé ce que je pensais devoir fonctionner, j'ai échoué et je suis passé à autre chose). Dans tous les cas, le compilateur devrait être en mesure d'insérer le tableau en transformation vectorielle, comme le fait Clang avec O2 activé GodBolt.la source
Comme il a été souligné, il n'est pas possible d'initialiser un vecteur de type move-only avec une liste d'initialiseurs. La solution proposée à l'origine par @Johannes fonctionne très bien, mais j'ai une autre idée ... Que faire si nous ne créons pas un tableau temporaire puis déplaçons des éléments de là dans le vecteur, mais utilisons le placement
new
pour initialiser ce tableau déjà à la place du bloc de mémoire du vecteur?Voici ma fonction pour initialiser un vecteur de
unique_ptr
's en utilisant un pack d'arguments:la source
result.data()
n'est pas un pointeur vers une mémoire aléatoire. C'est un pointeur vers un objet . Pensez à ce qui arrive à ce pauvre objet lorsque vous en placez un nouveau dessus.