2009-09-01 25 views
5

Esta es una pregunta realmente fácil, estoy seguro, pero agradecería la ayuda. :)Ayuda con la asignación C++ semi-compleja

Aquí es mi variable en el archivo .h:

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

Aquí soy yo tratando de asignar un valor:

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

he añadido algunos paréntesis adicionales al tratar de resolver esto con el fin para asegurarse de que los derefs se estaban procesando en el orden correcto; desafortunadamente, todavía no funciona. Mi aplicación simplemente se bloquea al ejecutar esta línea. Lo tengo envuelto en una prueba {} catch {}, pero parece que no se lanza ninguna excepción. No uso C++ muy a menudo y me pregunto si alguien me puede decir lo que estoy haciendo incorrectamente.

Aquí es la relación que estoy tratando de modelo:

Lista de números de transacción (enteros), debe ser ordenada por la clave.

Para cada número de transacción, tengo dos tipos de documentos, pagos y facturas (cubos representados por 0 y luego 1, respectivamente, en mi struct datos arriba)

En cada cubo tipo, hay puede ser uno o más documentos, Estos documentos deben ser ordenados por ID (iddoc)

Cada correspondiente DocID enlaces a una cadena que consiste en una lista separada por comas de f archivos en el sistema de archivos para su procesamiento.

Si cree que hay una mejor estructura de datos para usar, me interesaría saberlo.

EDIT: Sé que hay muchas formas mejores de hacerlo. El escenario fue que me entregaron un montón de código C++ horrible y lleno de MFC y me dijeron que hiciera algo ayer. Básicamente se redujo a obtener la estructura de datos allí, cargarla y luego enviarla a otro lugar. Estaba tratando de golpearlo rápidamente cuando hice esta pregunta. Aunque aprecio las sugerencias de diseño.

+3

Me gustaría deshacerme de la CString y usar std :: string. ¿El mapa (y las subpartes del mapa) ya está poblado? Puede estar intentando acceder/asignar posiciones vacías. ¿Qué está tratando de lograr? Eso parece un código horrible para mí. – Tim

+0

también - ¿qué son docnum y transnum? – Tim

+0

Estoy de acuerdo con tim. Cada vez que vea clases de contenedores anidados como esa, es una buena señal de que necesita crear su propia clase para representar parte o la totalidad de la estructura de datos que está definiendo. – rmeador

Respuesta

17

La forma en que std::map funciona es que asignará un nodo al que está intentando hacer referencia si aún no existe. Eso significa que a menos que esté asignando su (s) submapa (s) e insertándolos en su (s) supermapa (s), se le darán punteros a la memoria que no le pertenece. En ese momento, cuando trates de escribir en esa memoria, se bloqueará.

¿Se deben asignar los mapas?Si no se puede cambiar el tipo de:

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

y su llamada puede ser:

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

Voy a dar una oportunidad. Gracias. – cakeforcerberus

+0

Perfecto. No hay comentarios "horribles" regaños o inútiles. Solo una respuesta a la pregunta. Gracias Señor. : D – cakeforcerberus

11

Esa línea es manera demasiado compleja.

Tienes que dividirlo en pedazos más pequeños, convirtiendo cada pieza en una variable con nombre.

+5

Estoy de acuerdo. Este código parece una optimización prematura, en el sentido de intentar reducir el número de líneas de código. – mmr

5

Si se declara que:

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

usted debería ser capaz de hacer esto:

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

cuidado con los espacios faltantes entre '>' s (como se señala en la respuesta de fbereteon). – patros

+1

Normalmente me olvido de ellos hasta que no se compile :) – crashmstr

1

Probablemente esté desreferenciando un NULL o wild p Ointer en algún punto de esa monstruosidad. Ese tipo de cosas no generará una excepción, solo causará un error de segmentación (o el equivalente de su plataforma).

13

En primer lugar, typedef estas cosas, y se hace mucho más fácil:

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; 

en cuenta que debe casi siempre prefiere que apilar a la asignación dinámica. ¡En segundo lugar, estás haciendo demasiado en línea!

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

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

Ahora bien, si necesita depurar puede comprobar fácilmente esos valores, y es más fácil ver el lugar donde quiere cometer errores.

Creo que con más información podemos hacer que este trabajo sea mucho más simple. No puedo pensar por qué en la Tierra necesitarías algo como esto.

+1

+1 para el uso de typedefs. Sin embargo, iría más lejos y los usaría para evitar múltiples usos del operador [] en la misma línea al definir una referencia al valor de retorno de cada operador []. Además, los dos puntos deben marcarse const para garantizar que el compilador los optimice por usted. – Troubadour

2

Simplemente por diversión: ¿Por qué no hacer una colección de estos?

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

Sólo va para una lectura directa de lo que está tratando de modelar en las estructuras de datos simples que terminamos con esto.

std::map es un contenedor ordenado por lo que terminará con los pedidos que usted requirió. Al evitar el uso explícito de punteros y permitir que el contenedor administre la memoria dinámica, el modelo es más fácil de usar y menos propenso a errores.

Si tiene la posibilidad de obtener más tipos de documentos que solo pagos y facturas, entonces puedo hacer que el tipo de documento sea una enumeración y la transacción un mapa del tipo de 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; 

    // ... 
}