2
votes

Existe-t-il une manière transparente d'utiliser unique_ptr dans les conteneurs std?

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.

  • Existe-t-il des implémentations de conteneurs std pour unique_ptr? En particulier std :: map .
  • Comment une interface transparente serait-elle mise en œuvre?


4 commentaires

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.


3 Réponses :


1
votes

Je voudrais utiliser tbl.insert ({id, m}); et tbl [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 exemple

template <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)...));
    }
};

1 commentaires

Il semble que j'ai besoin d'écrire moi-même un dérivé de std :: map .



10
votes

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 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));
}

dans insert , vous pouvez également utiliser std :: move pour transférer la propriété de la collection.

p >


0 commentaires

3
votes

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;                                                                                                                               
}

Démo en direct


0 commentaires