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 *);
};
Est-ce un quiz? Savez-vous ce que sont les défauts? –
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
@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