2009-09-01 43 views
5

這是一個非常簡單的問題,我敢肯定,但我會很感激幫助。 :)幫助半複雜的C + +分配

這裏是我的變量在.h文件:

map<int, map<int, map<int, CString>*>*> batch; 

這裏就是我試圖分配一個值:

((*((*(batch[atoi(transnum)]))[1]))[atoi(*docnum)]) = page; 

我增加了一些額外的括號,而試圖以這出確保derefs以正確的順序處理 - 不幸的是,它仍然無法正常工作。運行此行時,我的應用程序崩潰。我把它封裝在一個try {} catch {}中,但是沒有出現異常。我不經常使用C++,並且想知道是否有人能告訴我我做錯了什麼。

這裏有我想要的模型之間的關係:

交易確認碼(整數)的列表,需要通過鍵排序。

對於每個事務號碼,我有兩個類型的文檔,付款和發票(由0表示的桶,然後在上述我的數據結構1分別)

在每種類型的桶,有可以一個或多個文檔,這些文件需要由ID(文檔ID)進行排序

每個文檔ID鏈接到由逗號分隔的F列表的字符串iles在文件系統上進行處理。

如果您認爲有更好的數據結構可供使用,我很樂意聽到它。

編輯:我知道有很多更好的方法來做到這一點。這種情況是,我收到了一堆令人恐懼的MFC錯誤的C++代碼,並告訴我昨天做了一些事情。它基本上歸結爲在那裏獲得數據結構,將其加載並將其輸出到其他地方。當我問這個問題時,我只是想盡快把它趕出去。我欣賞設計建議。

+3

我會擺脫CString並使用std :: string。地圖(和地圖的子部分)是否已經填充?您可能試圖訪問/分配空位。你想達到什麼目的?這對我來說看起來很可怕。 – Tim 2009-09-01 18:47:54

+0

也 - 什麼是docnum和transnum? – Tim 2009-09-01 18:49:55

+0

我同意蒂姆。每當你看到這樣的嵌套容器類時,這是一個好兆頭,你需要創建自己的類來表示你定義的一些或全部數據結構。 – rmeador 2009-09-01 18:50:07

回答

17

工作方式std::map的工作原理是,它將分配一個節點,如果它不存在,它將嘗試引用它。這意味着除非你分配你的子圖並將它們插入到你的超級圖中,否則你將得到指向你不擁有的內存的指針。當你嘗試寫入該內存時,你會崩潰。

地圖是否需要分配堆?如果沒有,你可以改變類型:

map<int, map<int, map<int, CString> > > batch; // don't forget the spaces 

,您的電話可以是:

batch[atoi(transnum)][1][atoi(*docnum)] = page; 
+0

我要給這個鏡頭。謝謝。 – cakeforcerberus 2009-09-01 18:49:33

+0

完美。沒有責罵或無用的「可怕的」評論。只是對這個問題的回答。謝謝你,先生。 :D – cakeforcerberus 2009-09-02 14:18:06

11

那條線是的方式太複雜了。

你需要把它分解成小塊,把每一塊變成一個命名變量。

+5

我同意。這個代碼看起來像是一些過早的優化,從減少代碼行數的意義上說。 – mmr 2009-09-01 18:46:53

5

如果你把它聲明:

map<int, map<int, map<int, CString> > > batch;//no asterisks! 

你應該能夠做到這一點:

batch[atoi(transnum)][1][atoi(*docnum)] = page; 
+0

注意'>'之間缺失的空格(正如fbereteon的答案中指出的那樣)。 – patros 2009-09-01 19:17:46

+1

我通常會忘記這些,直到它不能編譯:) – crashmstr 2009-09-01 19:26:54

1

你可能會解引用NULL或wild p在那個怪物的某個點上。這種事情不會拋出異常,它只會導致分段錯誤(或您的平臺的等價物)。

13

首先,typedef這些事情,它變得更加容易:

typedef std::map<int, CString> page_map; 
typedef std::map<int, page_map> document_map; 
typedef std::map<int, document_map> batch_map; 

batch_map batch; 

注意,你應該總是喜歡他堆到動態分配。其次,你做得太多了!

int transNumber = atoi(transnum); 
int docNumber = atoi(*docnum); // why is docnum a pointer? 

batch[transNumber ][1][docNumber] = page; 

現在,如果您需要調試,您可以輕鬆檢查這些值,並且更容易看出您會犯哪些錯誤。

我想更多的信息可以使這項工作更簡單。我想不出爲什麼在地球上你需要這樣的東西。

+1

+1使用typedefs。我會進一步討論,並且通過定義對每個運算符[]的返回值的引用,實際使用它們來避免在同一行上多次使用operator []。此外,這兩個int應該標記爲const,以確保編譯器爲您優化它們。 – Troubadour 2009-09-01 19:57:29

2

只是爲了好玩: 爲什麼不把這些收集起來呢?

typedef int transaction_key; 
typedef int doc_id; 

class Transaction 
{ 
public: 

    Transaction(transaction_key key) : m_key(key) {} 

    AddPaymentDoc(doc_id, const std::string&); 
    AddInvoiceDoc(doc_id, const std::string&); 
    // I'd probably have these methods return a unique ID actually, rather than 
    // create it yourself... or they can return void and you pass in the doc id. 


    // exception handling/other handling for attempting to reference using a bad id 
    std::string GetPayment(doc_id); 
    std::string GetInvoice(doc_id); 

    std::map <doc_id, std::string> GetPayments() {return Payments;} 
    std::map <doc_id, std::string> GetInvoices() {return Invoices;} 

private: 
    transaction_key m_key; 
    std::map <doc_id, std::string> Payments; 
    std::map <doc_id, std::string> Invoices;  
}; 
1

只是想直接閱讀您正在嘗試建模的簡單數據結構。

std::map是一個有序的容器,所以你最終得到你需要的順序。通過避免顯式使用指針並允許容器管理動態內存,該模型使用起來更簡單並且不易出錯。

如果您有更多文檔類型而不僅僅是付款和發票的潛力,那麼我可能會將文檔類型設置爲枚舉,並將事務映射到文檔類型爲DocumentMap

#include <map> 
#include <string> 

// Map of docid to comma separated string of files 
typedef std::map<int, std::string> DocumentMap; 

struct Transaction 
{ 
    DocumentMap payments; 
    DocumentMap invoices; 
}; 

// map of transaction id to transaction contents 
typedef std::map<int, Transaction> TransactionMap; 

TransactionMap batch; 

void foo(TransactionMap& batch) 
{ 
    // ... 

    batch[transno].invoices[docno] = page; 

    // ... 
}