2011-07-31 68 views
3

我正在編寫C++代碼來處理從實驗室測量中填充的一串直方圖。當我嘗試更好地組織問題時,我遇到了問題,並且我認爲我的問題來自錯誤處理指針和/或結構。初始化和維護結構體的結構

我的原始設計看起來是這樣的:

// the following are member variables 
Histogram *MassHistograms[3]; 
Histogram *MomentumHistograms[3]; 
Histogram *PositionHistograms[3]; 

,其中每個陣列的元素0相應於一個實驗室測量,每個元件1對應於另一個,等等。我可以經由MassHistograms[0]或訪問各個直方圖相似,而且工作正常。然而,該組織對我來說似乎並不合適 - 如果我要執行新的測量,則必須爲每個直方圖數組添加一個元素。相反,我想出了

struct Measurement { 
    Histogram *MassHistogram; 
    Histogram *MomentumHistogram; 
    Histogram *PositionHistogram; 
}; 

隨着複雜性的添加了一層,我更想根據已對他們的數據進行處理,以捆綁這些測量,所以我做了

struct MeasurementSet { 
    Measurement SignalMeasurement; 
    Measurement BackgroundMeasurement; 
}; 

我覺得這個安排更合理和可擴展性,但它不工作;-)如果我有一個像

MeasurementSet ms; 
Measurement m = ms.SignalMeasurement; 
Histogram *h = m.MassHistogram; 

代碼,然後嘗試做的東西與h,我得到分段故障。由於類似的代碼以前工作正常,我認爲我沒有正確處理我的代碼中的結構。具體來說,結構是否需要以任何方式顯式初始化? (Histogram由別人的圖書館提供,只是宣佈Histogram *SomeHistograms[4]之前就已經初始化了。)

我很感謝反饋意見。我用Python和Clojure的體面familar,但我有限的C++的知識並不延伸到[什麼似乎像]的關懷和結構的飼養:-)


我最終什麼事做的奧祕

我轉身Measurement成一個全面的類:

class Measurement { 
    Measurement() { 
     MassHistogram = new Histogram(); 
     MomentumHistogram = new Histogram(); 
     PositionHistogram = new Histogram(); 
    }; 

    ~Measurement() { 
     delete MassHistogram; 
     delete MomentumHistogram; 
     delete PositionHistogram; 
    }; 

    Histogram *MassHistogram; 
    Histogram *MomentumHistogram; 
    Histogram *PositionHistogram; 
} 

(通用Histogram()構造我稱之爲正常工作)我有被總是通過引用傳遞Measurement解決了問題等問題;否則,將在接收到Measurement的任何函數結束時調用析構函數,並且下一次嘗試使用其中一個直方圖執行某些操作時會發生段錯誤。

謝謝大家的回答!

+0

嘗試閱讀直方圖庫 – lovesh

回答

1

你確定Histogram *SomeHistograms[4]初始化數據?你如何填充直方圖結構?

這裏的問題不是指向你的指針。當你這樣做時:MeasurementSet ms;它聲明瞭一個MeasurementSet類型的'自動變量'。這意味着MeasurementSet的所有內存都已分配並準備就緒。 MeasurementSet又有兩個類型爲Measurement的變量,它們也被「分配」和「準備就緒」。測量反過來又有3個類型的Histogram *變量,它們也被「分配」和「準備好去」......但是等等!類型'直方圖*'是一個'指針'。這意味着它是一個地址 - 一個32位或64位(或任何位)值,用於描述實際的內存位置。就是這樣。這取決於你是否要指出某些東西 - 把東西放在那個位置。在它指向任何東西之前,它會有字面意義上的隨機數據(或者是數據,或者一些特殊的調試數據,或者類似的東西) - 關鍵是如果你試圖用它做什麼,你會出現分段錯誤,因爲您可能會嘗試讀取程序不應該讀取的部分數據。

在C++中,結構幾乎是完全一樣的東西爲一類(有Python中的類似的概念),而且您通常會分配一個像這樣:後

m.MassHistogram = new Histogram(); 

...中,直方圖已準備就緒。但是,YMMV:你可以自己分配一個嗎?或者你只能從某個圖書館得到一個,或者從一個閱讀設備中獲得一個?此外,雖然你可以做我寫的東西,但它不一定是'漂亮'。一個C++ - ic解決方案將分配到一個構造函數(如init在python中),並在析構函數中刪除。

+0

你說「一個C++ - ic解決方案將把分配在一個構造函數中......」這是否意味着我應該在這裏創建類而不是結構,所以我可以確保一切都是'new'd和'delete'd自動在類的構造函數/析構函數中? – bdesham

+0

是的。順便說一句,一個結構與一個類是一樣的,只有默認情況下所有的都是'public'。 – aib

1

當你的結構體包含一個指針時,你必須自己初始化該變量。 例

struct foo 
{ 
    int *value; 
}; 

foo bar; 
// bar.value so far is not initialized and points to a random piece of data 

bar.value = new int(0); 
// bar.value now points to a int with the value 0 

// remember, that you have to delete everything that you new'd, once your done with it: 
delete bar.value; 

1

你知道,你的Measurement定義不分配實際Histogram的記憶?在你的代碼中,m.MassHistogram是一個懸掛(未初始化)的指針,它不指向任何測量的Histogram,也不指向任何能夠存儲Histogram的存儲器。正如@Nari Rennlos剛剛發佈的那樣,您需要將其指向現有(或新分配的)Histogram

你的第三方庫的界面是什麼樣的?如果完全有可能的話,你應該有一個Measurement包含3 Histogram s(而不是3指針Histogram s)。這樣,當你創建一個Measurement或一個MeasurementSet將爲你創建對應的Histogram,同樣也可以銷燬。如果您仍需要一個指針,你可以使用&操作:

struct Measurement2 { 
    Histogram MassHistogram; 
    Histogram MomentumHistogram; 
    Histogram PositionHistogram; 
}; 

MeasurementSet2 ms; 
Histogram *h = &ms.SignalMeasurement.MassHistogram; //h valid as long as ms lives 

還要注意的是,只要你不指針(或引用)工作,對象將被複制和值賦值:

MeasurementSet ms;     //6 uninitialized pointers to Histograms 
Measurement m = ms.SignalMeasurement; //3 more pointers, values taken from first 3 above 
Histogram *h = m.MassHistogram;  //one more pointer, same uninitialized value 

雖然指針已經初始化,但是這時所有10個指針都會指向一個實際的Histogram

更糟糕,如果你有具體的成員,而不是指針:

MeasurementSet2 ms;     //6 Histograms 
Measurement2 m = ms.SignalMeasurement; //3 more Histograms, copies of first 3 above 
Histogram h = m.MassHistogram;   //one more Histogram 

h.firstPoint = 42; 
m.MassHistogram.firstPoint = 43; 
ms.SignalMeasurement.MassHistogram.firstPoint = 44; 

...現在你有3個稍有不同的質量信號直方圖2對同動量和位置信號直方圖,以及三重背景直方圖。

+0

OK的文件,假設我有一個帶有一個實例變量'MeasurementSet MyMeasurementSet'的類'Foo',並假設像你所建議的那樣,每個'MeasurementSet'由包含'Histogram's(* not * pointers)的'Measurement'組成。如果我將MyMeasurementSet傳遞給某個類方法,那麼該函數是否能夠影響實例變量MyMeasurementSet中的Histogram?或者我需要通過引用傳遞'MyMeasurementSet'才能做類似的事情? – bdesham

+0

您需要通過引用傳遞,或者使用指針或引用。 – aib

1

首先,請記住結構和類幾乎是完全相同的東西。唯一的區別是,默認情況下,結構成員是公共的,並且默認情況下,類成員是私有的。 但其餘的完全一樣。

其次,仔細區分指針和對象。

如果我寫的柱狀圖的數據

Histogram h;

空間將被分配,它的構造函數將被調用。 (A構建體與完全相同的名稱作爲類中的方法,此處Historgram())

如果我寫

Histogram* h; 

我聲明瞭將被用來作爲32/64位的可變一個指向內存的指針。它以一個隨機值初始化。危險!

如果我寫

Histogram* h = new Histogram(); 

內存將一個直方圖的數據成員進行分配,它的構造函數將被調用。內存中的地址將存儲在「h」中。

如果我寫

Histogram* copy = h; 

我再次聲明指向完全相同的地址在內存中爲h

如果我寫了一個32/64位可變

Histogram* h = new Historgram; 
Histogram* copy = h; 
delete h; 

發生以下情況

  1. 內存分配給直方圖對象
  2. 直方圖的構造函數將被調用(即使您沒有編寫它,編譯器也會生成一個)。
  3. h將包含此對象的內存地址
  4. 刪除操作員將調用直方圖的析構函數(即使您沒有編寫它,編譯器將生成一個)。
  5. 爲直方圖對象分配的內存將被釋放
  6. 副本仍將包含用於分配對象的內存地址。但是你不允許使用它。它被稱爲「懸擺指針」
  7. 轟的內容將是不確定的

總之:在你的代碼中的「n.MassHistogram」指的是內存中的任意區域。不要使用它。無論是分配它首先使用運營商的「新」,或者宣佈其爲「直方圖」(對象而不是指針)

歡迎CPP:d