2009-09-01 13 views
5

Questa è una domanda molto semplice, ma sono sicuro che apprezzerei l'aiuto. :)Aiuto con assegnazione C++ semi-complessa

Ecco il mio variabile nel file .h:

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

Ecco me cercando di assegnare un valore:

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

ho aggiunto qualche parentesi in più durante il tentativo di capire questo al fine per assicurarci che i derefs venissero processati nel giusto ordine - sfortunatamente, non funziona ancora. La mia applicazione si blocca quando si esegue questa linea. Lo ho avvolto in una prova {} catch {}, ma non sembra che venga lanciata alcuna eccezione. Non uso C++ molto spesso e mi chiedo se qualcuno possa dirmi cosa sto facendo in modo errato.

Ecco il rapporto che sto cercando di modello:

Elenco dei numeri di transazione (interi), deve essere ordinato a chiave.

Per ciascun numero di transazione, ho due tipi di documenti, pagamenti e fatture (secchi rappresentate da 0 e poi 1, rispettivamente, a mio struct dati sopra riportati)

In ciascun segmento tipo, non ci può essere uno o più documenti, Questi documenti devono essere ordinati da id (docid)

ogni link DocID una stringa che consiste in un elenco delimitato da virgole di f file sul file system per l'elaborazione.

Se pensi che ci sia una struttura dati migliore da usare, sarei interessato a sentirlo.

MODIFICA: So che ci sono molti modi migliori per farlo. Lo scenario era che mi è stato consegnato un mucchio di codice C++ orribile di MFC e mi è stato detto di fare qualcosa ieri. Fondamentalmente si è ridotto a inserire la struttura dei dati, caricandola e poi trasferendola da qualche altra parte. Stavo solo cercando di batterlo velocemente quando ho fatto questa domanda. Apprezzo comunque i suggerimenti sul design.

+3

Mi piacerebbe liberarmi di CString e utilizzare std :: string. La mappa (e le sottoparti della mappa) è già popolata? Potresti provare ad accedere/assegnare posizioni vuote. Cosa stai cercando di realizzare? Mi sembra un codice orribile. – Tim

+0

anche - cosa sono docnum e transnum? – Tim

+0

Sono d'accordo con tim. Ogni volta che vedi classi contenitore annidate in questo modo, è un buon segno che devi creare la tua classe per rappresentare una parte o tutta la struttura dati che stai definendo. – rmeador

risposta

17

Il modo in cui funziona std::map è che allocherà un nodo che si sta tentando di fare riferimento se non esiste ancora. Ciò significa che, a meno che tu non stia assegnando il tuo/i sottomesso/i e inserendolo nel/i tuo/i/i/i/i/i/i/i/i/i/i/i/i/i/i/i/i/i,/i/i,/i/i,/i/i/i,/i/i,/i/i,/i/i,/i,/i,/i,/i,/i; A quel punto, quando provi a scrivere su quella memoria, andrai in crash.

Le mappe devono essere allocate in heap?Se non è possibile modificare il tipo di:

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

e la chiamata può essere:

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

Ho intenzione di fare un tentativo. Grazie. – cakeforcerberus

+0

Perfetto. Nessun commento "orribile" sgrido o inutile. Solo una risposta alla domanda. Grazie Signore. : D – cakeforcerberus

11

Quella riga è via troppo complessa.

È necessario suddividerlo in parti più piccole, trasformando ciascun pezzo in una variabile denominata.

+5

Sono d'accordo. Questo codice sembra un'ottimizzazione prematura, nel senso di cercare di ridurre il numero di righe di codice. – mmr

5

Se si dichiara che:

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

si dovrebbe essere in grado di fare questo:

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

fai attenzione agli spazi mancanti tra ">" (come indicato nella risposta di fbereteon). – patros

+1

Di solito me ne dimentico finché non si compila :) – crashmstr

1

Probabilmente stai dereferenziando un NULL o un selvaggio p ointer ad un certo punto in quella mostruosità. Questo tipo di cose non genererà un'eccezione, causerà solo un errore di segmentazione (o l'equivalente della tua piattaforma).

13

In primo luogo, typedef queste cose, e diventa molto più facile:

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; 

nota che si dovrebbe quasi sempre preferisce lui impilare ad assegnare dinamicamente. In secondo luogo, stai facendo troppo in una riga!

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

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

Ora, se è necessario eseguire il debug è possibile controllare facilmente questi valori, ed è più facile vedere dove ci si commettono errori.

Penso che con ulteriori informazioni potremmo fare questo lavoro molto più semplicemente. Non riesco a pensare al perché sulla Terra avresti bisogno di qualcosa del genere.

+1

+1 per l'uso di typedef. Andrei oltre e li userei effettivamente per evitare molteplici usi dell'operatore [] sulla stessa linea definendo un riferimento al valore di ritorno di ciascun operatore []. Inoltre, i due int sono contrassegnati come const per garantire che il compilatore li ottimizzi per te. – Troubadour

2

Solo per divertimento: Perché non creare una raccolta di questi?

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

Giusto per una lettura diretta di ciò che si sta tentando di modellare in strutture di dati semplici, ho finito con questo.

std::map è un contenitore ordinato in modo da terminare con gli ordini richiesti. Evitando l'uso esplicito di puntatori e consentendo al contenitore di gestire la memoria dinamica, il modello è più semplice da utilizzare e meno soggetto a errori.

Se si dispone del potenziale di più tipi di documenti rispetto ai soli pagamenti e fatture, è possibile che il tipo di documento sia un'enumerazione e la transazione una mappa dal tipo di documento a 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; 

    // ... 
}