2009-09-01 7 views
5

To naprawdę łatwe pytanie, ale jestem wdzięczny za pomoc. :)Pomoc przy częściowo złożonym przypisaniu C++

Oto moja zmienna w pliku .h:

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

Oto ja próbuje przypisać wartość:

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

dodałem jakieś dodatkowe nawiasy podczas próby rysunek to w porządku aby upewnić się, że derefy były przetwarzane we właściwej kolejności - niestety nadal nie działa. Moja aplikacja ulega awarii po uruchomieniu tej linii. Mam go zapakowany w try {} catch {}, ale nie wydaje się, aby wyjątek został zgłoszony. Nie używam C++ bardzo często i zastanawiam się, czy ktoś może mi powiedzieć, co robię niepoprawnie.

Oto relacja Próbuję modelu:

Lista liczby transakcji (liczby całkowite), musi być uporządkowane według klucza.

Dla każdej liczby transakcji, mam dwa rodzajów z dokumentów, płatności i faktur (wiadrach reprezentowanych przez 0, a następnie 1 odpowiednio w moim struktury danych powyżej)

W każdym segmencie typu, istnieje może być jeden lub więcej dokumentów, dokumenty te muszą być zamawiane przez id (docId)

Każdy docId linki do łańcucha, który składa się z listy przecinkowym f iles w systemie plików do przetwarzania.

Jeśli uważasz, że istnieje lepsza struktura danych do wykorzystania, byłbym zainteresowany, aby to usłyszeć.

EDYCJA: Wiem, że istnieje wiele lepszych sposobów, aby to zrobić. Scenariusz był taki, że dostałem stertę okropnego kodu C++ z MFC i powiedziałem, żeby coś wczoraj zrobiło. Zasadniczo sprowadzała się do uzyskania struktury danych, ładowania jej, a następnie wyprowadzania w inne miejsce. Próbowałem go szybko rozwalić, gdy zadałem to pytanie. Doceniam jednak sugestie dotyczące projektu.

+3

Pozbyłbym się CStringa i użyłbym std :: string. Czy mapa (i podelementy mapy) jest już wypełniona? Być może próbujesz uzyskać dostęp do pustych pozycji lub je przypisać. Co próbujesz osiągnąć? Wygląda mi to na okropny kod. – Tim

+0

także - czym są dokumenty i transnum? – Tim

+0

Zgadzam się z Timem. Za każdym razem, gdy widzisz zagnieżdżone klasy kontenerów, jest to dobry znak, że musisz utworzyć własną klasę, która będzie reprezentować niektóre lub wszystkie zdefiniowane struktury danych. – rmeador

Odpowiedz

17

Sposób działania std::map polega na tym, że przydzieli on węzeł, który próbujesz odwołać, jeśli jeszcze nie istnieje. Oznacza to, że jeśli nie przypisujesz swoich submapów i wstawiasz je do swoich supermapów, otrzymasz wskaźniki do pamięci, której nie jesteś właścicielem. W tym momencie, kiedy spróbujesz napisać do tej pamięci, ulegniesz awarii.

Czy mapy muszą mieć przydzielone sterty?Jeśli nie można zmienić typ do:

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

i rozmowa może być:

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

Mam zamiar dać temu szansę. Dzięki. – cakeforcerberus

+0

Idealny. Bez zbeształ ani bezużytecznych "okropnych" komentarzy. Tylko odpowiedź na pytanie. Dziękuję Panu. : D – cakeforcerberus

11

Ta linia to sposób zbyt skomplikowany.

Musisz rozbić go na mniejsze części, zamieniając każdy element w nazwaną zmienną.

+5

Zgadzam się. Ten kod wygląda jak przedwczesna optymalizacja, w sensie próby zredukowania liczby linii kodu. – mmr

5

Jeśli zadeklarujesz go:

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

powinieneś być w stanie to zrobić:

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

uważaj na brakujące spacje między ">" (jak wskazano w odpowiedzi fbereteona). – patros

+1

Zwykle o nich zapominam, dopóki się nie skompiluje :) – crashmstr

1

Prawdopodobnie dereferencje NULL lub dzikie p ointer w jakimś punkcie tego potworności. Tego typu rzeczy nie wyrzucą wyjątku, spowoduje to jedynie błąd segmentacji (lub jego odpowiednik w swojej platformie).

13

Najpierw typedef te rzeczy, i to staje się o wiele łatwiejsze:

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; 

pamiętać, że powinien on prawie zawsze wolą układać do dynamicznego przydzielania. Po drugie, robisz za dużo w linii!

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

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

Teraz, jeśli potrzebujesz debugowania, możesz łatwo sprawdzić te wartości i łatwiej zauważyć, gdzie popełnisz błędy.

Myślę, że dzięki większej ilości informacji możemy sprawić, by ta praca była o wiele prostsza. Nie mogę wymyślić, dlaczego na Ziemi potrzebujesz czegoś takiego.

+1

+1 za użycie typedefs. Posunąłbym się jednak dalej i faktycznie użyłbym ich, aby uniknąć wielu zastosowań operatora [] na tej samej linii, definiując odniesienie do wartości zwracanej każdego operatora []. Ponadto oba ints powinny być oznaczone const, aby zapewnić, że kompilator je optymalizuje. – Troubadour

2

Dla zabawy: Dlaczego nie zrobić ich kolekcji?

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

Po prostu idąc do prostego czytania tego, co próbujesz modelować w proste struktury danych, skończyło się to.

std::map to zamówiony pojemnik, dzięki czemu otrzymasz zamówione produkty. Aby uniknąć wyraźnego użycia wskaźników i umożliwienia kontenerowi zarządzania pamięcią dynamiczną, model jest prostszy w użyciu i mniej podatny na błędy.

Jeśli masz potencjał na więcej typów dokumentów niż tylko płatności i faktury, mógłbym uczynić typ dokumentu wyliczeniem, a transakcja mapą z rodzaju dokumentu na 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; 

    // ... 
} 
Powiązane problemy