【发布时间】:2010-01-24 22:34:56
【问题描述】:
编辑:我在这里重新问了同样的问题(在解决了这个问题指出的问题之后):Why does this C++0x program generates unexpected output?
基本的想法是,如果你不小心,指向可移动的东西可能会给你带来一些奇怪的结果。
C++ 移动构造函数和移动赋值运算符看起来非常积极。并且它们可以用于复制构造函数没有意义的情况,因为它们不需要复制被指向的资源。
但有些情况下,如果你不小心,它们会咬你。这一点尤其重要,因为我已经看到允许编译器生成移动构造函数的默认实现的建议。如果有人可以给我,我会提供一个链接。
所以,这里有一些可能不完全明显的缺陷的代码。我测试了代码以确保它在带有-std=gnuc++0x 标志的g++ 中编译。这些缺陷是什么?您将如何修复它们?
#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 *);
};
【问题讨论】:
-
这是一个测验吗?你知道缺点是什么吗?
-
没有“正确”答案,因为这需要讨论。如果您希望它甚至有机会不被关闭,请使用更好的社区 Wiki....
-
@Greg Hewgill,我知道缺陷是什么。我注意到有几个人提出了他们知道答案的问题,因为他们认为这些问题的答案在网站上会很有用和有启发性。这是一个这样的问题。
-
@Omnifarious:对于这样的“我知道答案,你呢?”一种有用的问题,它必须足够具体,以至于可以从中学习的人实际上会找到它。目前它对此过于开放。如果您想为其他人尚未提出的问题提供答案,那么请让问题具体到想要的人会找到它。
-
@jalf,这是有道理的。我投票结束了这个问题,我会修改它并以不同的方式提问。
标签: c++ c++11 move-constructor