2009-11-21 65 views
1

內使用時我有一個簡單的類這些,也很簡單,構造函數:奇怪類行爲的Qt應用程序

audio::audio() { 
    channels = NULL; 
    nChannels = 0; 
} 

audio::audio(const char* filename) { 
    audio(); 
    getFromFile(filename); 
} 

(這是audio():channels(NULL), nChannles(0), loaded(false){...之前,我將在後面說爲什麼這個改變... )。功能getFromFile開始是這樣的:

void audio::getFromFile(const char* filename) { 
    baseUtils::dynVec<float> *chans; 
    if (channels != NULL) 
     deleteChannels(); 
    sox_format_t *in; 
    sox_sample_t buff[AUDIO_CLASS_READ_SAMPLES]; 
    sox_sample_t sample; 
... 

正如你所看到的,它會檢查是否loaded是真實的,如果它是運行在內部緩衝區一些delete(S)。當然,從構造函數中可以看到,第一次運行loaded爲false,那麼第二個構造函數會調用第一個構造函數,然後有loaded = false

如果我在一個簡單的命令行應用程序運行這個類,一切都正常運行。但如果我把它放在一個Qt應用程序,正是在做這個插槽:

void buttonPushed() { 

     QString s = QFileDialog::getOpenFileName(); 
     std::cout << "file choosen: " << s.toStdString() << "\n"; 
     sndfile = s.toStdString(); 
     if (aud == NULL){ 
      aud = new audio(sndfile.c_str()); 
      ui.widget->setAudio(aud); 
      ui.widget->update(); 
     } 
[...] 

將有channels != NULL(調用第二構造之後),並嘗試刪除未分配的指針(導致分段故障)。使用GDB我發現channels被設置爲一些奇怪的值,並且nChannels太...這聞起來像一個競爭條件,但顯然似乎並不是這種情況。我在插槽中放了一張支票,看看是否爲aud != NULL,以避免這種情況。你有什麼想法?爲什麼會發生?我試圖使用Valgrind,它說在channels != NULL我試圖做一個有未初始化值的條件跳轉!怎麼會這樣?那麼構造函數呢?

回答

9

的問題是在audio::audio(const char* filename)構造。第一個陳述是audio();,我相信你正試圖調用默認的構造函數。但是,C++不允許一個ctor調用另一個。所以你有未初始化的指針。如果你想做這樣的事情,可以寫一個名爲init()的私有方法,並從兩個構造函數中調用它。 audio();語句使用在此語句後立即銷燬的默認ctor創建臨時(未命名)音頻對象。因此,在此之後訪問的對象是具有未初始化指針的不同對象。

+2

audio();創建一個對象,但由於您沒有命名它,您以後無法訪問它。 – 2009-11-21 15:47:25

+0

'audio()'創建一個新的臨時'音頻'對象,不會將它存儲在任何變量中(它會立即被再次銷燬)。 – sth 2009-11-21 15:49:27

+0

你可以使用上面描述的init()方法,或者你可以對音頻進行子類化,爲它提供一個新的構造函數,並像下面這樣從新的構造函數中調用舊的:childClass():baseClass(){// ctor logic here } ....我想我更喜歡init()方法。 – 2009-11-21 15:51:07