2010-02-02 76 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); 
    } 
} 
相關問題