2010-02-02 53 views
2

这个程序:为什么这个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 

我有点困惑。当我添加一台记录仪时,似乎所有旧的传感器都被遗忘了。

+0

那是最短的你可以把它同时还展示了什么问题?越短越好。 – 2010-02-02 18:13:40

+0

@mmyers,我知道,但我认为那是尽可能短的。有两个独立类的对象通过增强信号机制进行交互。 – Omnifarious 2010-02-02 18:18:07

回答

2

记录器可以在内存中移动,因为您在创建它们时添加到矢量中,但是您正在为它们绑定信号,因为您正在这样做。

+0

关于如何解决该问题的任何想法?我真的需要按价值存储记录。 – Omnifarious 2010-02-02 18:37:52

+1

我会使用deque代替。 – ergosys 2010-02-02 18:40:56

0

给记录器索引传感器矢量而不是指向传感器的指针。只要您不删除传感器,就可以正常工作。

+0

我只是试过,并没有改变任何东西。我认为它与指向记录仪的指针有关,它隐藏在信号内部,而不是指向给记录仪的信号。 – Omnifarious 2010-02-02 19:24:58

-1

你有没有试过使用直数组而不是:: std :: vector?我知道:: std :: vector是一个时髦的东西,但它不是一个真正的矢量(更像是半列半列)。

+0

说什么?他需要一个动态数组,一个“直线”数组不是动态的。说一个矢量不是矢量有点奇怪。 – GManNickG 2010-08-07 21:54:26

+0

不 - 他只需要保留两个正常的索引并将新对象放入稳定的槽中,就这些了。它甚至可以通过再一次改进而成为线程安全的。 在抗议之前阅读STL向量的实际来源,然后阅读该向量的定义。使持误导性的名称永久存在只会令人困惑的问题。向量和列表具有非常不同的行为,复杂性和线程安全性。不幸的是,STL创造了一个命名混乱,我们能做的最好的事情就是意识到它。 – ZXX 2010-08-07 23:10:59

+0

@zb_z:使用@name回复。 “矢量”的定义是什么?有一个由标准设定的界面和要求,没有“the”的定义。没有STL,有一个标准库。向量是一个完全合理的名字;它包含一系列可索引值,就像数学向量一样。仅仅因为你可以改变尺寸并不意味着什么。不,当他需要一个*动态数组*时,插槽系统不会解决任何问题。你不能猜测你需要多少个插槽,并且用一些硬编码的大小来重新发明vector也是愚蠢的。只需使用'deque'作为适当的选择。 – GManNickG 2010-08-08 08:59:48

0

Ergosys已经描述了问题的原因。缺少的是解决方案:确保在绑定信号之前将所有记录器和传感器添加到矢量中。这样他们的地址将会改变。

这里的主回路的修订:

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 (unsigned int i = 0; i < 9; ++i) { 
    if (i % sensor_every == 0) { 
     for (auto r = recorders.begin(); r != recorders.end(); ++r) { 
     shared_ptr<Sensor> sp = sensors[i/sensor_every]; 
     r->addSensor(*sp); 
     } 
    } 
    for (auto s = sensors.begin(); s != sensors.end(); ++s, val *= 1.001) { 
     (*s)->updateSensor(val); 
    } 
} 
相关问题