2014-01-15 50 views
1

在JNI .cpp文件中,我有一個帶有SoundTouch *的結構(SoundTouch是一個C++音頻處理,我將其用於Android項目中),並初始化該結構作爲全局對象這樣的向量:將全局對象初始化爲指針是成功的唯一方法

struct SoundTouchExt 
{ 
    SoundTouch* sTouch; 
    queue<signed char>* fBufferOut; 
    int channels; 
    int sampleRate; 
    float tempoChange; 
    int pitchSemi; 
    int bytesPerSample; 

    SoundTouchExt() 
    { 
     sTouch = new SoundTouch(); 
     fBufferOut = new queue<signed char>(); 
    } 
}; 

const int MAX_TRACKS = 16; 

vector<SoundTouchExt> sProcessors(MAX_TRACKS); 

這工作,至少如果我只用SoundTouchExt的一個在我的程序在同一時間對象(也就是那種一個不同的故事,但可能與 - 在播放多個實例時會導致輸出失真)。

但是,如果我宣佈它像這樣SoundTouch sTouch;,註釋掉new並相應地改變它的使用(->.),指針引用,我編譯罰款,但我得到一個故障11(賽格故障)儘快當程序嘗試使用該對象時。

這裏的地方出現這種情況:

... 
    SoundTouchExt& soundTouch = sProcessors.at(track); 
    setup(soundTouch, channels, samplingRate, bytesPerSample, tempo, pitchSemi); 
} 

static void setup(SoundTouchExt& soundTouch, int channels, int sampleRate, int bytesPerSample, float tempoChange, float pitchSemi) 
{ 
    SoundTouch& sTouch = soundTouch.sTouch; 

    soundTouch.channels = channels; 
    soundTouch.sampleRate = sampleRate; 
    soundTouch.bytesPerSample = bytesPerSample; 
    soundTouch.tempoChange = tempoChange; 
    soundTouch.pitchSemi = pitchSemi; 

    sTouch.setSampleRate(sampleRate); 
    sTouch.setChannels(channels); 
... 
} 

一個小小的研究,我想這可能是static intialization order fiasco的一個實例。我沒有在庫源代碼中看到任何全局變量,但我對C++知之甚少,無法知道還有什麼其他要查找的東西。

我的觀察對圖書館有什麼建議(或者我沒有正確地做某件事)?

回答

4

我相信你的SoundTouch結構/類在其複製構造函數和/或賦值運算符中存在問題。或者你甚至沒有寫出那些,但需要。

爲什麼在我看不到SoundTouch的代碼時這麼說?那麼...

你的SoundTouchExt有如何管理其sTouch成員(以及fBufferOut)的問題。每個實例創建它自己的sTouch,但是當您的對象被複制時,您沒有複製構造函數或賦值操作符來處理sTouch成員。編譯器提供的默認值只會簡單地進行淺層成員複製。因此,如果一個SoundTouchExt對象被分配給另一個,那麼它們最終都會以指向同一SoundTouch的sTouch指針結束。我懷疑你曾經打算過這樣的事情發生。但是由於你也沒有析構函數來清理這些分配,所以你可能會放棄這種情況一段時間(因爲泄漏的內存很容易忽略)。

看起來你確實發生了在使用vector<SoundTouchExt>時逃脫它。一個矢量管理一個內部數組。將條目添加到矢量中時,它有時可能會耗盡當前數組中的空間,因此需要創建一個新數組來保存其他條目。這樣做時,它必須將舊數組中的所有條目複製到新數組中。因此,它使用SoundTouchExt的複製構造函數和/或賦值運算符。您不會注意到這一點,因爲使用同一個SoundTouch的兩個SoundTouchExt實例的情況僅在舊數組中的一個被破壞之前短暫存在。由於SoundTouchExt沒有析構函數,因此沒有任何問題。

現在考慮一下當sTouch成員是實際的SoundTouch實例而不是指針時情況如何改變。在這種情況下,當複製SoundTouchExt對象並因此複製sTouch成員時,這意味着編譯器將使用SoundTouch拷貝構造函數/賦值運算符。而且我們知道你的媒介可能會導致這種情況發生。

由於您的SoundTouchExt存在我所描述的複製問題,因此我懷疑您的SoundTouch也存在問題。如果是這樣的話,那麼當你嘗試使用sTouch成員時,它可能已經被複制,從而導致某種問題。那個問題會導致你的崩潰。

所以解決的事情,你有幾種選擇:

  • 確保被複制時,所有的相關對象正確行事。這可能意味着實現複製構造函數和賦值運算符。在這種情況下,您最有可能應該按照Rule of Three執行析構函數。
  • 或者禁用它們的拷貝構造函數和賦值操作符(將它們聲明爲私有但不實現),以免它們意外被使用。那可能需要一些其他的重構,比如你的矢量使用。雖然如果您有C++ 11功能可用,您可能可以使用移動操作符/構造函數,以便您的對象可以像現在這樣在標準容器中工作,但在適當時可以正確傳輸其成員。析構函數可能仍然是必需的。
  • 或者用某些智能指針(如unique_ptr)替換那些原始指針,它們可以自動管理任何分配了new的內容,而無需編寫任何附加代碼。
+0

確實,我當然不打算指向一個SoundTouch實例。你幾乎完美地把所有東西都打在了頭上,謝謝。 –

相關問題