为什么这个 C++0x 程序会生成意外的输出?
这个程序:
test_header.hpp
#include <boost/signal.hpp>
#include <utility>
class Sensor;
class Recorder : public ::boost::signals::trackable {
public:
explicit Recorder(int id) : id_(id) {}
// Cannot be copied
Recorder(const Recorder &) = delete;
Recorder &operator =(const Recorder &) = delete;
// But can be moved so it can be stored in a vector.
// There's a proposal for having a compiler generated default for this that would be
// very convenient.
Recorder(Recorder &&b) : id_(b.id_) {
b.id_ = -1;
}
Recorder &operator =(Recorder &&b) {
id_ = b.id_;
b.id_ = -1;
return *this;
}
void recordSensor(const Sensor &s);
void addSensor(Sensor &s);
private:
int id_;
char space_[1312];
};
class Sensor {
public:
typedef ::boost::signal<void (const Sensor &)> sigtype_t;
explicit Sensor(int id) : val_(0), id_(id) { }
void notify(const sigtype_t::slot_type &slot) { signal_.connect(slot); }
void updateSensor(double newval) { val_ = newval; signal_(*this); }
double getValue() const { return val_; }
int getId() const { return id_; }
private:
sigtype_t signal_;
double val_;
const int id_;
};
test_body.cpp
#include "test_header.hpp"
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
void Recorder::addSensor(Sensor &s)
{
::std::cout << "Recorder #" << id_
<< " now recording Sensor #" << s.getId() << '\n';
::std::cout.flush();
s.notify(::boost::bind(&Recorder::recordSensor, this, _1));
}
void Recorder::recordSensor(const Sensor &s)
{
::std::cout << "Recorder #" << id_ << " - new value for sensor named Sensor #"
<< s.getId() << ": " << s.getValue() << '\n';
::std::cout.flush();
}
int main(int argc, const char *argv[])
{
using ::boost::shared_ptr;
using ::std::vector;
vector<Recorder> recorders;
vector<shared_ptr<Sensor> > sensors;
double val = 0.1;
static const unsigned int recorder_every = 4;
static const unsigned int sensor_every = 2;
for (unsigned int i = 0; i < 9; ++i) {
if (i % recorder_every == 0) {
recorders.push_back(Recorder(i / recorder_every));
}
if (i % sensor_every == 0) {
shared_ptr<Sensor> sp(new Sensor(i / sensor_every));
sensors.push_back(sp);
for (auto r = recorders.begin(); r != recorders.end(); ++r) {
r->addSensor(*sp);
}
}
for (auto s = sensors.begin(); s != sensors.end(); ++s, val *= 1.001) {
(*s)->updateSensor(val);
}
}
}
我得到这个输出:
Recorder #0 now recording Sensor #0
Recorder #0 - new value for sensor named Sensor #0: 0.1
Recorder #0 - new value for sensor named Sensor #0: 0.1001
Recorder #0 now recording Sensor #1
Recorder #0 - new value for sensor named Sensor #0: 0.1002
Recorder #0 - new value for sensor named Sensor #1: 0.1003
Recorder #0 - new value for sensor named Sensor #0: 0.100401
Recorder #0 - new value for sensor named Sensor #1: 0.100501
Recorder #0 now recording Sensor #2
Recorder #1 now recording Sensor #2
Recorder #0 - new value for sensor named Sensor #2: 0.100803
Recorder #1 - new value for sensor named Sensor #2: 0.100803
Recorder #0 - new value for sensor named Sensor #2: 0.101106
Recorder #1 - new value for sensor named Sensor #2: 0.101106
Recorder #0 now recording Sensor #3
Recorder #1 now recording Sensor #3
Recorder #0 - new value for sensor named Sensor #2: 0.101409
Recorder #1 - new value for sensor named Sensor #2: 0.101409
Recorder #0 - new value for sensor named Sensor #3: 0.101511
Recorder #1 - new value for sensor named Sensor #3: 0.101511
Recorder #0 - new value for sensor named Sensor #2: 0.101815
Recorder #1 - new value for sensor named Sensor #2: 0.101815
Recorder #0 - new value for sensor named Sensor #3: 0.101917
Recorder #1 - new value for sensor named Sensor #3: 0.101917
Recorder #0 now recording Sensor #4
Recorder #1 now recording Sensor #4
Recorder #2 now recording Sensor #4
Recorder #0 - new value for sensor named Sensor #4: 0.102428
Recorder #1 - new value for sensor named Sensor #4: 0.102428
Recorder #2 - new value for sensor named Sensor #4: 0.102428
我有点困惑。当我添加记录器时,似乎所有旧传感器都被遗忘了。
This program:
test_header.hpp
#include <boost/signal.hpp>
#include <utility>
class Sensor;
class Recorder : public ::boost::signals::trackable {
public:
explicit Recorder(int id) : id_(id) {}
// Cannot be copied
Recorder(const Recorder &) = delete;
Recorder &operator =(const Recorder &) = delete;
// But can be moved so it can be stored in a vector.
// There's a proposal for having a compiler generated default for this that would be
// very convenient.
Recorder(Recorder &&b) : id_(b.id_) {
b.id_ = -1;
}
Recorder &operator =(Recorder &&b) {
id_ = b.id_;
b.id_ = -1;
return *this;
}
void recordSensor(const Sensor &s);
void addSensor(Sensor &s);
private:
int id_;
char space_[1312];
};
class Sensor {
public:
typedef ::boost::signal<void (const Sensor &)> sigtype_t;
explicit Sensor(int id) : val_(0), id_(id) { }
void notify(const sigtype_t::slot_type &slot) { signal_.connect(slot); }
void updateSensor(double newval) { val_ = newval; signal_(*this); }
double getValue() const { return val_; }
int getId() const { return id_; }
private:
sigtype_t signal_;
double val_;
const int id_;
};
test_body.cpp
#include "test_header.hpp"
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
void Recorder::addSensor(Sensor &s)
{
::std::cout << "Recorder #" << id_
<< " now recording Sensor #" << s.getId() << '\n';
::std::cout.flush();
s.notify(::boost::bind(&Recorder::recordSensor, this, _1));
}
void Recorder::recordSensor(const Sensor &s)
{
::std::cout << "Recorder #" << id_ << " - new value for sensor named Sensor #"
<< s.getId() << ": " << s.getValue() << '\n';
::std::cout.flush();
}
int main(int argc, const char *argv[])
{
using ::boost::shared_ptr;
using ::std::vector;
vector<Recorder> recorders;
vector<shared_ptr<Sensor> > sensors;
double val = 0.1;
static const unsigned int recorder_every = 4;
static const unsigned int sensor_every = 2;
for (unsigned int i = 0; i < 9; ++i) {
if (i % recorder_every == 0) {
recorders.push_back(Recorder(i / recorder_every));
}
if (i % sensor_every == 0) {
shared_ptr<Sensor> sp(new Sensor(i / sensor_every));
sensors.push_back(sp);
for (auto r = recorders.begin(); r != recorders.end(); ++r) {
r->addSensor(*sp);
}
}
for (auto s = sensors.begin(); s != sensors.end(); ++s, val *= 1.001) {
(*s)->updateSensor(val);
}
}
}
And I get this output:
Recorder #0 now recording Sensor #0
Recorder #0 - new value for sensor named Sensor #0: 0.1
Recorder #0 - new value for sensor named Sensor #0: 0.1001
Recorder #0 now recording Sensor #1
Recorder #0 - new value for sensor named Sensor #0: 0.1002
Recorder #0 - new value for sensor named Sensor #1: 0.1003
Recorder #0 - new value for sensor named Sensor #0: 0.100401
Recorder #0 - new value for sensor named Sensor #1: 0.100501
Recorder #0 now recording Sensor #2
Recorder #1 now recording Sensor #2
Recorder #0 - new value for sensor named Sensor #2: 0.100803
Recorder #1 - new value for sensor named Sensor #2: 0.100803
Recorder #0 - new value for sensor named Sensor #2: 0.101106
Recorder #1 - new value for sensor named Sensor #2: 0.101106
Recorder #0 now recording Sensor #3
Recorder #1 now recording Sensor #3
Recorder #0 - new value for sensor named Sensor #2: 0.101409
Recorder #1 - new value for sensor named Sensor #2: 0.101409
Recorder #0 - new value for sensor named Sensor #3: 0.101511
Recorder #1 - new value for sensor named Sensor #3: 0.101511
Recorder #0 - new value for sensor named Sensor #2: 0.101815
Recorder #1 - new value for sensor named Sensor #2: 0.101815
Recorder #0 - new value for sensor named Sensor #3: 0.101917
Recorder #1 - new value for sensor named Sensor #3: 0.101917
Recorder #0 now recording Sensor #4
Recorder #1 now recording Sensor #4
Recorder #2 now recording Sensor #4
Recorder #0 - new value for sensor named Sensor #4: 0.102428
Recorder #1 - new value for sensor named Sensor #4: 0.102428
Recorder #2 - new value for sensor named Sensor #4: 0.102428
I'm kind of confused. When I add a Recorder it seems like all the old sensors are forgotten about.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
记录器可以在内存中移动,因为您在创建它们时将其添加到向量中,但在执行此操作时您将绑定到它们以发出信号。
Recorders can move in memory because you are adding to a vector as you create them, but you are binding to them for signaling as you are doing this.
为记录器提供传感器矢量的索引,而不是指向传感器的指针。只要不删除传感器就可以正常工作。
Give the recorder an index to the sensor vector instead of a pointer to the sensor. Works fine as long as you don't delete sensors.
Ergosys 已经描述了问题的原因。缺少的是解决方案:确保在绑定信号之前将所有记录器和传感器添加到向量中。这样他们的地址就会改变。
这是主循环的修订版:
Ergosys already described the reason for the problem. What's missing is the solution: Make sure you finish adding all the recorders and sensors to the vectors before you bind the signals. That way their addresses will be done changing.
Here's a revision of the main loop:
您是否尝试过使用直接数组而不是 ::std::vector ?我知道 ::std::vector 是一个时髦的东西,但它并不是真正的向量(更像是半列表半数组)。
Have you tried using straight arrays instead of ::std::vector ? I know that ::std::vector is a fashionable thing but it's not really a vector (more like a half-list half-array).