2010-01-24 5 views
0

Edit: Je re-posé cette même question (après la fixation des problèmes constatés avec cette question) ici: Why does this C++0x program generates unexpected output?C++ 0x constructeur move Gotcha

L'idée de base est que pointant vers des choses mobiles peut vous net des résultats bizarres si vous ne faites pas attention. Le constructeur de déplacement C++ et l'opérateur d'affectation de mouvement semblent être des choses vraiment positives. Et ils peuvent être utilisés dans des situations où le constructeur de copie n'a aucun sens, car ils ne nécessitent pas de duplication des ressources pointées.

Mais il y a des cas où ils vous mordront si vous ne faites pas attention. Et ceci est particulièrement pertinent car j'ai vu des propositions pour permettre au compilateur de générer des implémentations par défaut du constructeur de déplacement. Je fournirai un lien si quelqu'un peut m'en donner un. Donc, voici un code qui a quelques défauts qui peuvent ne pas être complètement évidents. J'ai testé le code pour m'assurer qu'il compile en g ++ avec le drapeau -std=gnuc++0x. Quels sont ces défauts et comment les réparer?

#if (__cplusplus <= 199711L) && !defined(__GXX_EXPERIMENTAL_CXX0X__) 
    #error This requires c++0x 
#endif 

#include <unordered_set> 
#include <vector> 
#include <utility> 
#include <algorithm> 

class ObserverInterface { 
public: 
    virtual ~ObserverInterface() {} 

    virtual void observedChanged() = 0; 
    virtual void observedGoingAway() = 0; 
}; 

class Observed { 
private: 
    typedef ::std::unordered_set<ObserverInterface *> obcontainer_t; 

public: 
    Observed() {} 
    Observed(const Observed &) = delete; 
    const Observed &operator =(const Observed &b) = delete; 
    // g++ does not currently support defaulting the move constructor. 
    Observed(Observed &&b) : observers_(::std::move(b.observers_)) { } 
    // g++ does not currently support defaulting move assignment. 
    const Observed &operator =(Observed &&b) { 
     observers_ = ::std::move(b.observers_); 
     return *this; 
    } 
    virtual ~Observed() { 
     for (auto i(observers_.begin()); i != observers_.end(); ++i) { 
     (*i)->observedGoingAway(); 
     } 
    } 

    void unObserve(ObserverInterface *v) { 
     auto loc(observers_.find(v)); 
     if (loc != observers_.end()) { 
     observers_.erase(loc); 
     } 
    } 

    void changed() { 
     if (!observers_.empty()) { 
     // Copy observers_ to bector so unObserve works 
     ::std::vector<ObserverInterface *> tmp; 
     tmp.reserve(observers_.size()); 
     tmp.assign(observers_.begin(), observers_.end()); 

     for (auto i(tmp.begin()); i != tmp.end(); ++i) { 
      (*i)->observedChanged(); 
     } 
     } 
    } 

private: 
    obcontainer_t observers_; 
}; 

class Observer : public ObserverInterface { 
public: 
    Observer() {} 
    Observer(const Observer &) = delete; 
    const Observer &operator =(const Observer &b) = delete; 
    // g++ does not currently support defaulting the move constructor. 
    Observer(Observer &&b) : observed_(b.observed_) { 
     b.observed_ = 0; 
     return *this; 
    } 
    // g++ does not currently support defaulting move assignment. 
    const Observer &operator =(Observer &&b) { 
     observed_ = b.observed_; 
     b.observed_ = 0; 
     return *this; 
    } 
    virtual ~Observer() { 
     if (observed_) { 
     observed_->unObserve(this); 
     observed_ = 0; 
     } 
    } 

    virtual void observedChanged() { 
     doStuffWith(observed_); 
    } 
    virtual void observedGoingAway() { 
     observed_ = 0; 
    } 

private: 
    Observed *observed_; 

    // Defined elsewhere 
    void doStuffWith(Observed *); 
}; 
+1

Est-ce un quiz? Savez-vous ce que sont les défauts? –

+3

il n'y a pas de réponse "correcte" car cela nécessite une discussion. Better Community Wiki si vous voulez que cela ait même une chance de ne pas se fermer .... – Earlz

+1

@Greg Hewgill, je sais ce que sont les défauts. Je remarque qu'il y a plusieurs personnes qui posent des questions auxquelles elles connaissent les réponses parce qu'elles pensent que les réponses aux questions seront utiles et instructives sur le site. C'est une telle question. – Omnifarious

Répondre

5

Il y a beaucoup de problèmes avec le code.

  1. Observer::observed_ est laissé dans le constructeur non initialisée par défaut, ce qui conduit à un comportement non défini lorsque le destructor est appelé.
  2. Aucune valeur mais 0 est affectée à Observer::observed_, ce qui rend la variable superflue.
  3. Même s'il existait un moyen d'associer un observateur à un observateur, vous ne vous enregistrez pas de nouveau lorsque vous déplacez l'observateur.
  4. Vous essayez de renvoyer une valeur à partir du constructeur de mouvement de l'observateur.
  5. Boost.Signals résout déjà tout problème que vous essayez de résoudre.
  6. Il est plus idiomatique de renvoyer une référence non-const à partir d'opérateurs d'affectation.
+0

* soupir * Merci Vous avez mis en évidence suffisamment de problèmes qui ne sont pas liés à ce que je pensais Je pense que je devrais supprimer la question et recommencer – Omnifarious

+0

Cependant, vous avez un des problèmes auxquels je pensais. – Omnifarious