Existe-t-il une manière transparente d'utiliser std :: unique_ptr
dans les conteneurs?
#include <iostream> #include <memory> #include <map> struct method { virtual ~method() { std::cout << "f\n"; }; }; typedef std::unique_ptr<method> MPTR; std::map<int, MPTR> tbl; void insert(int id, method *m) { tbl.insert({id,std::unique_ptr<method>(m)}); }; void set(int id, method *m) { tbl[id] = std::unique_ptr<method>(m); }; int main(int argc, char **argv) { insert(1,new method()); set(1,new method()); return 0; }
Je voudrais utiliser tbl.insert ({id, m});
et tbl [id] = m;
etc. au lieu d'avoir à envelopper / déplier pour chaque accès.
std :: map
. 3 Réponses :
Je voudrais utiliser
tbl.insert ({id, m});
ettbl [id] = m;
au lieu d'avoir à envelopper / déplier pour chaque accès.Pourquoi? Cela masque les informations du lecteur. Il est important de savoir si quelque chose est alloué dynamiquement ou non.
Existe-t-il des implémentations de conteneurs std pour unique_ptr? En particulier
std :: map
.Pas dans la bibliothèque standard.
Comment une interface transparente serait-elle mise en œuvre?
Stockez un conteneur normal dans votre wrapper, fournissez des fonctions de transfert qui créent
unique_ptr
si nécessaire. Les itérateurs peuvent se dérouler automatiquement. Par exempletemplate <typename T> class unique_ptr_vector { std::vector<std::unique_ptr<T>> _data; public: template <typename... Ts> void emplace_back(Ts&&... xs) { _data.emplace_back(std::make_unique<T>(std::forward<Ts>(xs)...)); } };
Il semble que j'ai besoin d'écrire moi-même un dérivé de std :: map
.
En général, nous ne voulons pas créer implicitement std :: unique_ptr
car qui peut être dangereux .
Dans cet exemple, je vous recommande de commencer par un dans unique_ptr plutôt qu'un simple
nouveau
. Cette garantit que toute la durée de vie est suivie . P > #include <memory>
int main(int argc, char **argv) {
auto m = std::make_unique<method>();
insert(1, std::move(m));
}
insert
, vous pouvez également utiliser std :: move
pour transférer la propriété de la collection.
Lorsque vous passez un pointeur brut dans une fonction, on ne sait généralement pas qui est censé conserver la propriété de l'objet pointé lorsque la fonction se termine - l'appelant ou l'appelé. Il n'y a rien dans le langage pour spécifier ou imposer cela.
Il est donc généralement recommandé de ne transmettre un pointeur brut que lorsque l'appelé lit ou modifie l'objet mais que l'appelant est censé conserver la propriété.
Dans votre exemple, ce n'est pas le cas. Vous souhaitez que vos fonctions s'approprient les objets method
alloués. Donc, vous devriez changer vos fonctions pour passer des objets std::unique_ptr
par valeur, au lieu de passer des pointeurs bruts method *
. Cela rend très explicite le fait que la propriété devrait passer de l'appelant à l'appelé, par exemple:
#include <iostream> #include <memory> #include <map> struct method { virtual ~method() { std::cout << "f\n"; }; }; typedef std::unique_ptr<method> MPTR; std::map<int, MPTR> tbl; void insert(int id, MPTR m) { tbl.insert(std::make_pair(id, std::move(m))); }; void set(int id, MPTR m) { tbl[id] = std::move(m); }; int main() { insert(1, MPTR(new method)); // or insert(1, std:::make_unique<method>()) in C++14 and later set(1, MPTR(new method)); // or set(1, std:::make_unique<method>()) in C++14 and later return 0; }
Je ne comprends pas votre question: qu'essayez-vous de faire avec la carte et l'emballage?
@JVApen: Je veux une carte qui détruit ses éléments à la fin / lors de l'écrasement. J'utilise le pointeur brut en dehors du code. Je veux me débarrasser du bruit généré par le fait de devoir envelopper / déballer lors de l'enregistrement et également de l'accès.
Pourquoi voudriez-vous préférer les pointeurs bruts à l'unique?
@JVApen: pas besoin de pointeurs uniques à l'extérieur du code de la carte. Le cycle de vie est géré dans la carte uniquement. Ce serait idéal si le standard C ++ avait un quailifier appelé 'unique' pour les pointeurs et que C ++ pourrait le faire de manière transparente.