2016-12-01 4 views
2

je avais besoin d'utiliser une classe aujourd'hui qui a suivi cette conception de base:C++ déplacer la sémantique où aurait été il ne devrait pas être bénéficier

class Task { 
public: 
    Task() { 
     Handler::instance().add(this); 
    } 
    virtual void doSomething() = 0; 
}; 

class Handler { 
    std::vector<Task*> vec; 
    //yea yea, we are locking the option to use default constructor etc 
public: 
    static Handler& instance() { 
     static Handler handler; 
     return handler; 
    } 

    void add(Task* task) { 
     vec.push_back(task); 
    } 

    void handle() { 
     for (auto t : vec) { 
      t->doSomething(); 
     } 
    } 
}; 

template <class T, int SIZE> 
class MyTask : public Task { 
    T data[SIZE]; 
public: 
    virtual void doSomething() { 
     // actually do something 
    } 
}; 
//somewhere in the code: 
Handler::instance().handle(); 

maintenant, ma classe est quelque chose comme

class A { 
    MyTask<bool, 128> myTask; 
public: 
    A(int i) {} 
}; 

la manière Je voulais le faire est d'avoir une carte où les instances de A sont des valeurs

static std::map<int, A> map = { 
    {42, A(1948)}, 
    {88, A(-17)} 
}; 

d'abord pour clarifier quelque chose - ce code n Je dois utiliser un système embarqué en temps réel, donc je ne suis pas autorisé à allouer de la mémoire en utilisant du nouveau pour plusieurs raisons héritées. Mon problème était que les objets réels dans la carte n'étaient pas ceux que j'avais explicitement créés et donc ils ne se sont pas inscrits dans la classe Handler (donc je n'ai pas eu l'avantage des appels Handler :: handle) .

J'ai essayé de trouver une bonne façon de résoudre cela sans faire quelque chose de moche comme d'abord créer un tableau de A puis pointer seulement vers ces objets dans la carte par exemple.

Je n'ai jamais utilisé la sémantique de mouvement auparavant, mais j'ai lu un peu à leur sujet et j'ai pensé qu'ils pouvaient être ma solution. Cependant, après avoir lu this answer (en particulier le tout premier exemple), il m'a semblé que je ne pouvais vraiment rien tirer profit de l'utilisation de la sémantique de déplacement.

Je l'ai essayé quand même (coz pourquoi diable ne pas ...) et a fait quelque chose comme ceci:

static std::map<int, A> map = { 
    {42, std::move(A(1948))}, 
    {88, std::move(A(-17))} 
}; 

maintenant ma grande surprise, le constructeur de copie de MyTask appelait encore (je mets imprimer dans ce pour vérifier) ​​mais pour une raison quelconque maintenant l'enregistrement du gestionnaire a bien fonctionné et mes instances ont apprécié les appels doSomething().

J'ai essayé de lire plus à fond sur std :: move pour comprendre ce qui s'est exactement passé là mais je n'ai pas trouvé la réponse.

quelqu'un peut-il l'expliquer? std :: move déplace le ce pointeur en quelque sorte? ou peut-être juste fait l'enregistrement se produise correctement en quelque sorte et n'a rien réel à voir avec le mouvement tentative

grâce

modifier:

de préciser davantage ce que je demande:

Je comprends que l'utilisation de std :: move ne contribuait pas à ce qui est fait là-bas.

Mais pour une raison quelconque, mes objets ont été récupérés dans la carte pour obtenir les appels doSomething() via le gestionnaire. Je cherche cette raison

sur une note de côté car il appartient probablement à une question différente - existe-t-il un moyen décent pour initialiser une carte de cette façon sans le temps de créer chaque objet deux fois?

+1

Cette question n'est toujours pas très claire pour moi. Votre exemple n'a pas vraiment de sens - d'où vient ce 'std :: map' et comment cela est-il en quelque sorte lié à' Handler'? S'il vous plaît créer un réel [mcve] – AndyG

+0

pourquoi importe-t-il où la carte entre en jeu? et le gestionnaire enregistre les objets Tâches créés – user2717954

+0

À côté: si vous n'êtes pas autorisé à faire des allocations de mémoire, alors vous n'êtes probablement pas autorisé à utiliser 'std :: map' (sauf si vous lui donnez un allocateur personnalisé qui ne le fait pas violer vos contraintes). – Hurkyl

Répondre

1

Votre question a beaucoup plus de choses que nécessaire mais je pense avoir compris la question fondamentale ici.Le constructeur std::map reçoit un initialization_list, vous appelez (5) from this list. Les objets sont copiés à partir d'un initializer_list lors d'une itération sur celui-ci plutôt que déplacé car une copie d'un initializer_list ne copie pas les objets sous-jacents. La même chose affecte d'autres conteneurs std, voici un exemple avec vector à démontrer. (live link)

#include <vector> 
#include <iostream> 

struct Printer { 
    Printer() { std::cout << "default ctor\n"; } 
    Printer(const Printer&) { std::cout << "copy\n"; } 
    Printer(Printer&&) { std::cout << "move\n"; } 
}; 

int main() { 
    std::vector<Printer> v = {Printer{}}; 
} 

si vous utilisez {std::move(Printer{})} vous allez ajouter un autre mouvement dans le mélange que le compilateur ne peut pas facilement s'optimiser loin.

+0

Je comprends en quelque sorte, la vraie question est pourquoi at-il réellement résoudre mon problème? – user2717954

+0

Si votre problème est que vous ne pouvez pas utiliser 'new' alors ce n'est pas le cas. carte utilise nouveau –

+0

Je peux utiliser une carte (oui, je sais que cela semble stupide, mais ce sont les règles de mon entreprise) – user2717954