2011-04-05 46 views
11

我想創建一些Timer類,它每N秒打印一次「text」,其中N將在構造函數中初始化。C++ bad_weak_ptr錯誤

#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <boost/enable_shared_from_this.hpp> 

#include <iostream> 

class Timer : public boost::enable_shared_from_this<Timer> 
{ 
public: 
    Timer (const double interval) : interval_sec(interval) 
    { 
     io_service_ = new boost::asio::io_service; 
     timer_  = new boost::asio::deadline_timer (* io_service_); 
     start(); 
     io_service_ -> run(); 
    } 

    void start () 
    { 
     timer_ -> expires_from_now(boost::posix_time::seconds(0)); 
     timer_ -> async_wait(boost::bind(&Timer::handler 
             , shared_from_this() 
             , boost::asio::placeholders::error 
             ) 
          ); 
    } 

private: 
    void handler(const boost::system::error_code& error) 
    { 
     if (error) 
     { 
      std::cerr << error.message() << std::endl; 
      return; 
     } 

     printf("text\n"); 
     timer_ -> expires_from_now(boost::posix_time::seconds(interval_sec)); 
     timer_ -> async_wait(boost::bind(&Timer::handler 
             , shared_from_this() 
             , boost::asio::placeholders::error 
             ) 
          ); 
    } 

private: 
    boost::asio::io_service * io_service_; 
    boost::asio::deadline_timer * timer_; 
    double interval_sec; 
}; 

int main() 
{ 
    boost::shared_ptr<Timer> timer(new Timer (10)); 
    return 0; 
} 

但我有bad_weak_ptr錯誤。

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_weak_ptr> >' 
    what(): tr1::bad_weak_ptr 
Aborted 

我在做什麼錯,我該如何解決?

+1

你是否已經在調試器中加入了代碼?我猜''main()'在定時器觸發之前會返回,導致'timer'被破壞。你確定'async_wait'持有共享對象嗎? – 2011-04-05 21:30:36

+2

你可能也想做一些關於內存泄漏的事情。用'new'創建成員幾乎不是一個好主意。 – 2011-04-05 23:10:43

+2

在這個問題上有點OT,但是它是第一個搜索'boost :: bad_weak_ptr'的結果,所以我會在這裏寫這個。一個很好的'boost :: bad_weak_ptr'異常(拋出'boost :: exception_detail :: clone_impl '''後調用'terminate)也會拋出,如果試圖用'std :: shared_ptr '替換'boost :: shared_ptr ',所以要小心。 :) – Avio 2014-10-14 13:17:27

回答

26

問題很可能是您不能使用shared_from_this,直到對象實際上由共享指針管理爲止。一般來說,在構造函數中啓動線程或異步服務並不是一個好主意,因爲您可能會感到不幸,並且新線程可能會在構造函數完成之前啓動,從而在未完全構建的對象上執行。

在您的特定情況下,甚至更糟,因爲你進入你的Timer類的構造函數中的事件循環,這意味着控制永遠不會返回到main,對象從不在主力shared_ptr管理.. 。

你應該將調用start和調用run()到不同的功能,並呼籲從main後的物體在shared_ptr實際上是管理。

+0

在我看來,這是一種醜陋,我不能構建這個對象,並忘記它。我應該把它稱爲'start()'方法等等。順便說一句,我可以在'start()'函數中調用'io_service_ - > run();'嗎? – 2011-04-05 21:52:48

+0

@ garmOnboz1a:在創建一個對象並忘記它時沒有問題,只是沒有按照你所做的方式:即在對象在'shared_ptr'中管理之前調用'shared_from_this'時出現問題,並且調用'run'不會完成,而是抓住線程並執行事件循環。你可以從你想要的任何地方調用'io_service _-> run()',但是它會抓取線程的控制權,直到退出控制循環時纔會返回。誠懇地說,我不確定在那裏做這件事是否合理。 – 2011-04-05 22:48:03

+0

從設計角度來看,'Timer'只是其中一個可以註冊異步交互的潛在類(和對象),它在其中一個方法中捕獲線程是沒有意義的。考慮一下,如果'start'這樣做,那麼你就不能在每個線程中使用多個'Timer' - 即。每個計時器都會抓住它自己的線程...您應該閱讀異步編程教程,並嘗試理解這些示例以及它們爲什麼以這種方式構建。 – 2011-04-05 22:50:24

10

在致電shared_from_this()之前,您的課程需要存儲在shared_ptr中。這意味着你不能在構造函數中調用shared_from_this(),因爲直到構造函數完成之後,該對象纔會被放置到shared_ptr中。

這是這樣一種利用enable_shared_from_this類通常有一個start函數初始化做的最後的步驟,需要使用shared_from_this()的原因。該對象完全構造後需要調用該啓動函數,因此不能像構建函數那樣從內部調用。