Después de haber pasado los últimos 2 meses comiendo, durmiendo y respirando mapas, tengo una recomendación. Deje que el mapa asigne sus propios datos siempre que sea posible. Es mucho más limpio, exactamente por el tipo de razones que está resaltando aquí.
También hay algunas ventajas sutiles, como si está copiando datos de un archivo o socket a los datos del mapa, el almacenamiento de datos existe tan pronto como el nodo existe porque cuando el mapa llama a malloc() para asignar el nodo , asigna memoria tanto para la clave como para los datos. (AKA mapa [clave] .primero y mapa [clave] .segundo)
Esto le permite utilizar el operador de asignación en lugar de memcpy(), y requiere 1 llamada menos a malloc() - el que usted hace.
IC_CDR CDR, *pThisCDRLeafData; // a large struct{}
while(1 == fread(CDR, sizeof(CDR), 1, fp)) {
if(feof(fp)) {
printf("\nfread() failure in %s at line %i", __FILE__, __LINE__);
}
cdrMap[CDR.iGUID] = CDR; // no need for a malloc() and memcpy() here
pThisCDRLeafData = &cdrMap[CDR.iGUID]; // pointer to tree node's data
Algunas advertencias a tener en cuenta que vale la pena señalar aquí.
- no llame a malloc() o nueva en la línea de código que añade el nodo de árbol como su llamada a malloc() devolverá un puntero antes de la llamada del mapa para malloc() ha asignado un lugar para celebrar la regreso de tu malloc().
- en modo de depuración, esperamos tener problemas similares al intentar liberar() su memoria. Ambos me parecen problemas de compilación, pero al menos en MSVC 2012, existen y son un problema grave.
piense en dónde "anclar" sus mapas. IE: donde están declarados. No quiere que salgan del alcance por error. main {} siempre es seguro.
INT _tmain(INT argc, char* argv[]) {
IC_CDR CDR, *pThisCDRLeafData=NULL;
CDR_MAP cdrMap;
CUST_MAP custMap;
KCI_MAP kciMap;
que he tenido muy buena suerte, y estoy muy feliz con un mapa crítico asignar una estructura ya que es datos del nodo, y tener esa estructura "ancla" un mapa. Si bien las estructuras anónimas han sido abandonadas por C++ (una horrible y horrible decisión que DEBE revertirse), los mapas que son el primer miembro de la estructura funcionan igual que las estructuras anónimas. Muy pulido y limpio con cero efectos de tamaño. Pasar un puntero a la estructura de hoja, o una copia de la estructura por valor en una llamada a función, ambos funcionan muy bien. Muy recomendable.
- puede atrapar los valores de retorno de .insert para determinar si encontró un nodo existente en esa clave o si creó uno nuevo. (Ver # 12 para el código) Usar la notación del subíndice no permite esto. Sería mejor instalarlo y ponerlo, especialmente porque la notación [] no funciona con multimaps. (No tendría sentido hacerlo, ya que no hay una "clave", sino una serie de claves con los mismos valores en un multimap)
- puede, y debe, también atrapar las devoluciones para .erase y. empty() (SÍ, es molesto que algunas de estas cosas sean funciones y necesiten el() y algunos, como .erase, do not)
- puede obtener tanto el valor clave como el valor de datos para cualquier nodo del mapa usando .primer y .segundo, que todos los mapas, por convención, usan para devolver la clave y los datos respectivamente
ahórrese una GRAN cantidad de confusión y tipeo, y use typedefs para sus mapas, como tal.
typedef map<ULLNG, IC_CDR> CDR_MAP;
typedef map<ULLNG, pIC_CDR> CALL_MAP;
typedef struct {
CALL_MAP callMap;
ULNG Knt;
DBL BurnRateSec;
DBL DeciCents;
ULLNG tThen;
DBL OldKCIKey;
} CUST_SUM, *pCUST_SUM;
typedef map<ULNG,CUST_SUM> CUST_MAP, CUST_MAP;
typedef map<DBL,pCUST_SUM> KCI_MAP;
referencias de paso a los mapas utilizando el typedef y & operador como en
ULNG DestroyCustomer_callMap(CUST_SUM Summary, CDR_MAP& cdrMap, KCI_MAP& kciMap)
utilizar el "auto" tipo variable para iteradores. El compilador deducirá del tipo especificado en el resto del cuerpo del bucle for() qué tipo de tipo de mapa usará. ¡Está tan limpio que es casi mágico!
for(auto itr = Summary.callMap.begin(); itr!= Summary.callMap.end(); ++itr) {
definir algunas constantes evidentes para que el regreso de .erase y .empty() más meaningfull.
if(ERASE_SUCCESSFUL == cdrMap.erase (itr->second->iGUID)) {
dado que "punteros inteligentes" son en realidad sólo mantienen un contador de referencia, recuerde que siempre puede mantener su propia cuenta de referencia, una probablemente en un producto de limpieza, y de manera más evidente. Combinando esto con los números 5 y 10 anteriores, puedes escribir un buen código de limpieza como este.
#define Pear(x,y) std::make_pair(x,y) // some macro magic
auto res = pSumStruct->callMap.insert(Pear(pCDR->iGUID,pCDR));
if (! res.second) {
pCDR->RefKnt=2;
} else {
pCDR->RefKnt=1;
pSumStruct->Knt += 1;
}
usando un puntero a colgar en un nodo de mapa que asigna todo para sí, es decir: no hay punteros de usuario apuntando a malloc usuario() ed objetos, funciona bien, es potencialmente más eficiente, y y ser usado para mutar los datos de un nodo sin efectos secundarios en mi experiencia.
en el mismo tema, como un puntero se puede utilizar de manera muy eficaz para preservar el estado de un nodo, como en pThisCDRLeafData
anterior. Pasar esto a una función que muta/cambia los datos de ese nodo particular es más limpio que pasar una referencia al mapa y la clave necesaria para volver al nodo pThisCDRLeafData
está apuntando a.
iteradores no son mágicos. Son caros y lentos, ya que estás navegando por el mapa para obtener valores. Para un mapa con un millón de valores, puede leer un nodo basado en una clave a unos 20 millones por segundo. Con los iteradores es probablemente ~ 1000 veces más lento.
Creo que sobre covers por el momento. Se actualizará si algo de esto cambia o si hay ideas adicionales para compartir. Estoy especialmente disfrutando de usar el STL con código C. IE: no es una clase a la vista en ningún lado. Simplemente no tienen sentido en el contexto en el que estoy trabajando, y no es un problema. Buena suerte.
Intentar usar at() para acceder a él no le permitirá acceder a algo que no está allí, por ejemplo: http://ideone.com/ZeRTnd (aunque el elemento con la clave "B" se definió anteriormente, después de map.clear () al intentar acceder a la clave "B" obtienes la excepción '' std :: out_of_range'' –