2017-05-25 3 views
3

J'ai une classe contenant un tableau de style c géré avec unique_ptr. Je veux fournir un constructeur:Définir le membre de la classe unique_ptr <T[]> tableau sans copier

class A { 
    unique_ptr<T[]> p; 
public: 
    A(int d, X x) : p(new T[d]) { 
    //Transfer from x to p without copying 
    } 
} 

pour que je puisse construire mon objet avec quelque chose comme:

int main(..) { 
    A a{n,{expr1,expr2,..}}; 
} 

où {expr1, expr2, ..} contient les valeurs (évaluées lors de l'exécution) pour l'initialisation. Puisque cette liste est temporaire, il me semble que c'est un gaspillage de ressources pour la construire, copier ses valeurs dans l'objet réel et le jeter. Je pense qu'avec move semantincs, rvalues ​​et toutes les bonnes fonctionnalités de C++ 11 il devrait y avoir une solution pour cette tâche simple, mais je ne l'ai pas trouvée (je suis assez nouveau en C++).

Je voudrais coller avec les tableaux de style c et ne pas déplacer vers std :: vectors. Y a-t-il une solution?

+0

Que voulez-vous dire par "sans copier"? Vous voulez que l'allocation de tas soit initialisée avec les membres de données? – Justin

+0

* "Je voudrais coller avec les tableaux de style c et ne pas déplacer vers std :: vectors" * [sic] pourquoi ne voudriez-vous pas utiliser les fonctionnalités fournies par la bibliothèque du langage? Ne pas le faire s'appelle réinventer la roue. –

+0

@ nnn Legacy code, pour n'en nommer que quelques-uns. –

Répondre

2

Oui, vous pouvez utiliser le transfert parfait:

#include <memory> 
#include <string> 

struct S 
{ 
    S(int) {} 
    S(S const&) = delete; 
    S(S&&) = default; 
}; 

template<typename T> 
struct A 
{ 
    std::unique_ptr<T[]> p; 

    template<typename... Args> 
    A(int d, Args&&... args) 
     : p(new T[sizeof...(args)]{std::forward<Args>(args)...}) 
    { 
    } 
}; 

int main() 
{ 
    A<int> a(0, 1, 2, 3, 4); 

    A<std::string> b(0, "hello", "world!", "\n"); 

    S s(0); 
    A<S> c(0, std::move(s), 2, 3); 
} 
2

Il y a des points de remorquage que je voudrais faire ici.

  1. AFAICS, std::unique_ptr<T[]> vous offre très peu d'avantages sur la solution standard C++ d'utiliser un std::vector<T>, à savoir une empreinte mémoire réduite (64 au lieu de 128 octets pour le conteneur lui-même sur une machine 64 bits et peut-être aussi du montant de tas utilisé), mais voir la discussion here. Toute nouveauté de C++ doit rester à std::vector.

  2. La sémantique de déplacement n'est utile que pour les objets qui gèrent la mémoire sur le tas («magasin gratuit»). Donc, seulement si vos expr1, expr2 etc. sont des objets qui gardent eux-mêmes la trace de la mémoire allouée, est-ce que le déplacement a une signification quelconque. Cela ne semble pas le cas ici, alors copiez juste.

+0

Re. 2, 'T' pourrait être' std :: string' ou une classe plus compliquée –

+0

@Walter Je ne comprends pas complètement votre deuxième commentaire. Peut-être que je me trompe, mais je peux imaginer quelqu'un pour construire un objet temporaire sur la pile et "déplacer" cet objet en tant que membre d'une classe. – Teloze

+1

@ user8066678 Vous semblez n'avoir pas encore compris l'idée de bouger. Si vous créez un objet temporaire sur la pile, vous ne pouvez pas le déplacer. Déplacer signifie: copier le pointeur vers un objet sur le tas (plutôt que de copier l'objet lui-même), mais ensuite s'assurer que la variable pointeur copiée est réinitialisée à null. Il est semblable à ce que l'on appelle une «copie superficielle» (par ex.g. en python). – Walter