7
votes

Initialiser static std STD :: Carte avec une valeur unique_ptr en tant que valeur

Comment peut-on initialiser la carte statique, où la valeur est std :: unique_ptr code>?

static void f()
{
    static std::map<int, std::unique_ptr<MyClass>> = {
        { 0, std::make_unique<MyClass>() }
    };
}


1 commentaires

Vous devez fournir un nom de variable pour une chose.


3 Réponses :


8
votes

Le problème est que la construction de std :: initialiszer-list copie son contenu. ( objets dans std :: initialisizer_list sont intrinsèquement const ). Pour résoudre votre problème: vous pouvez initialiser la carte à partir d'une fonction distincte ... xxx

puis appelez-le xxx

voir < Un href = "http://coliru.stacked-crooked.com/a/dbc251e6248d4379" rel = "NOREFERRER"> Vivez sur Coliru


2 commentaires

Sera-ce une différence si init () retournera std :: map <...> && (rvalue)? C'est à dire. retourne une rvalue sera meilleur? UPD: avec rvalue il y aura un segfault


@Vladon, ce n'est pas simplement une persistimation de la performance, c'est aussi un bug. Vous retournerez un rvalue référence à un objet détruit. Voir Ce ... Le retour par valeur est extrêmement efficace dans des cas comme celui-ci, car c'est son Cerentiellement (c ++ 17) aller profiter RVO



1
votes

Une autre façon de faire cela est d'utiliser une lambda. C'est la même chose que d'utiliser une fonction distincte, mais met l'initialisation de la carte plus près de l'action. Dans ce cas, j'ai utilisé une combinaison d'un auto et d'un DeclType pour éviter de nommer le type de carte, mais c'est juste pour le plaisir.

Notez que l'argument passé dans la Lambda est une référence à un objet qui a Pas encore été construit au point de l'appel, nous ne devons donc pas y référoir de quelque manière que ce soit. Il n'est utilisé que pour la déduction de type. P>

#include <memory>
#include <map>
#include <utility>

struct MyClass {};

static auto& f()
{
  static auto mp = [mp = std::map<int, std::unique_ptr<MyClass>>{}]() mutable
  {
    mp.emplace(0, std::make_unique<MyClass>());
    mp.emplace(1, std::make_unique<MyClass>());
    return std::move(mp);
  }();
  return mp;
}

int main()
{
  auto& m = f();
}


0 commentaires

2
votes

Écriture du code de la crâche sur mesure semble ennuyeuse et gêne de la clarté.

Voici un code d'initialisation générique de conteneur générique raisonnablement efficace. Il stocke vos données dans un Std :: Array Code> Comme une liste d'initialistes, mais il passe au lieu de le faire const code>. P>

make_map code> prend un nombre pair d'éléments, le premier étant clé de la deuxième valeur. P> xxx pré>

ceci devrait le réduire à: p>

static std::map<int, std::unique_ptr<MyClass>> bob = 
  make_map(0, std::make_unique<MyClass>());


3 commentaires

@ U.Bulle j'ai corrigé 2 petites fautes de frappe et a ajouté un lien vers un exemple en direct qui compile.


J'ai mal classé et enlevé mon commentaire. Pour des raisons d'histoire, j'ai commenté cela sur cela indiquant une compilation échec de la commande Déballage de la commande dans les détails :: make_map et que cela me donne STD :: paire erreur. Tu as raison ça compile maintenant. J'aimerais être capable de l'utiliser sur mon code aussi, je ne sais pas ce qui l'oblige à échouer dans mon cas ici ici Stackoverflow .Com / Questions / 53806687 , c'est probablement un bogue sur le compilateur VStudio. Merci quand même si une solution très intéressante et cool!


@ U.bulle Compiler dans MSVC ? Je ne sais pas pourquoi cela ne sera pas compilé pour vous.