2012-05-22 16 views
7

Comencé un proyecto en C++. La administración de memoria en este lenguaje es nueva para mí.C++ Técnicas/prácticas de administración de memoria

Solía ​​crear objetos con new() y luego pasaba punteros y, aunque funcionaba, me costaba depurar y la gente me veía raro cuando veían el código. Estoy muy orgulloso del hecho de que no haya fugas o segfault (una vez corregido), pero realmente fue un gran esfuerzo.

list <struct Connection *> users; 

struct Connection * accept_connection (const char *name) { 
    struct Connection * new_node = new Connection(); 
    new_node->_data = ... // whatever, set it up here 
    return new_node; 
} 

struct Connection * new_user = accept_connection (const char *name); 
users.append (new_user); 

Tengo una nueva estrategia para esta próxima versión del proyecto. Hasta ahora, lo que estoy haciendo es crear objetos con new() y asignarles un número de identificación entero único. Luego almaceno el objeto en una tabla hash usando la ID como clave. Ahora los elementos se almacenan y pasan por el número entero de identificación y cuando necesita desviarlo, va a la tabla hash y le devuelve thing * o NULL. Por lo tanto, ya no experimento errores de puntero, pero la velocidad del código se reduce un poco.

typedef unsigned long ID_Number; 

// create a user and return the ID 
ID_Number create_user() { 
    ID_Number new_id = assign_unique_id(); 
    struct User * node = new User(); 
    node->_id = new_id; 
    node->_data = ... // whatever, set it up here 
    add_to_users_dict (new_id, node); 
    return new_id; 
} 

list <ID_Number> users; 

for_each (users.begin(), users.end(), process_user); 

void process_user (ID_Number i) { 
    struct User * u_ptr = lookup_user_dict (i); 
    if (u_ptr == NULL) { 
    // not found in dict 
    // somehow this guy was deleted 
    } else { 
    // we can do stuff with this guy 
    } 
} 

Ahora estoy especie de familiarizarse con los principios básicos de la programación, pero siendo un aficionado autodidacta No estoy familiarizado con las prácticas y herramientas de la industria. Lo que básicamente estoy pidiendo, son pautas sobre la administración de la memoria:

1) ¿Qué estoy haciendo bien o mal?

2) ¿Hay algún paquete o biblioteca que pueda usar que me ayude?

3) ¿Cuáles son las prácticas estándar de la industria?

4) Básicamente, ¿qué debo buscar en Google o comprar para kindle, etc.?

Hoy usualmente uso Python, maneja muchas cosas de "back-end" para mí, pero necesito C o C++ (supongo que estoy usando plain c más las librerías de stdC++, no estoy muy seguro de dónde la superposición entre los lenguajes es - solo sé que g ++ lo compila bien) para este proyecto en particular por razones de velocidad/rendimiento: aunque sospecho que algún genio matemático podría proporcionar soluciones algorítmicas que acelerarían su velocidad, aunque esa es una pregunta aparte.

+2

Comience mirando 'shared_ptr'. –

+0

La primera herramienta que utilizaría es valgrind: http://valgrind.org/docs/manual/QuickStart.html – Anycorn

+10

Buscar RAII. Esto es un poco loco. –

Respuesta

5

La mejor respuesta que puedo dar es que no debe usar punteros de la manera tradicional. C++ 11 ha cambiado la forma en que el programador trata la administración de la memoria.

En lugar de explicar cosas que ya han sido explicadas detalladamente por personas mucho más inteligentes que yo, solo proporcionaré algunos enlaces.

El primero que debería mirar es el artículo de Herb Sutter Elements of Modern C++ Style A continuación, ver el vídeo por Bjarne Stroustrup C++11 Style

Si usted es capaz de utilizar el nuevo estándar de C++ 11 que debiera, hace que la gestión de memoria mucho más limpio que antes.

+2

Y si no puede usar C++ 11 (¡llame a su headhunter!), Hay muchas cosas para no administrar la memoria manualmente que funciona con C++ 03. –

1

1) ¿Qué estoy haciendo bien o mal?

No está utilizando la terminología Adquisición de recursos inicialización (RAII) o la semántica moderna propiedad de C++.

2) ¿Hay algún paquete o biblioteca que pueda usar que me ayude?

Si realmente necesita pasar punteros, puede usar std :: unique_ptr y std :: shared_ptr. Pero antes de ir a eso, debe aprender a hacer que sus propios objetos se comporten como propietarios de recursos con semántica de RAII.

3) ¿Cuáles son las prácticas estándar de la industria?

4) Básicamente, ¿qué debo buscar en Google o comprar para kindle, etc.?

RAII

2

¿Qué estoy haciendo bien o mal?

Básicamente, ha creado un sistema que utiliza identificadores para referirse a objetos en lugar de punteros directos. Esto puede ser apropiado para algunos escenarios. Los sistemas operativos a menudo usan identificadores cuando el SO "posee" el objeto y gestiona su tiempo de vida, pero permite que un cliente se refiera a él.

¿Hay algún paquete o biblioteca que pueda usar que me ayude?

La biblioteca estándar en C++ moderna tiene shared_ptr y unique_ptr, que son punteros inteligentes que administran la vida útil de los objetos dinámicos. Son una excelente forma de usar RAII.

¿Cuáles son las prácticas estándar de la industria?

El estándar de facto en C++ es RAII - la asignación de recursos es la inicialización. RAII ata la asignación a los constructores y la desasignación a los destructores. Dado que C++ tiene garantías sólidas sobre cómo y cuándo se ejecutan los c'tors y d'ors, esto le proporciona una forma perfecta de administrar la vida útil de los objetos sin fugas. Los punteros inteligentes, shared_ptr y unique_ptr, también hacen explícita la propiedad del objeto.

Básicamente, ¿qué debo buscar en Google o comprar para kindle, etc.?

Buscar RAII.

1

Su primer error es utilizar new.

La memoria dinámica rara vez se necesita, y es incluso más rara de lo que se necesita "directamente": la mayoría de los objetos asignados dinámicamente viven dentro de un contenedor (como vector o map).

Su segundo error no es el uso de constructores, una vez que entienda lo que son invariantes de clase y cómo los constructores les permiten, entonces usted será capaz de tomar ventaja de RAII (Raii) y dejar de programar en C.

+0

Empecé a mirar RAII: ajuste el ctor/dtor para que se llame automáticamente al dtor cuando se retira la envoltura de la pila. Entonces, con RAII, ¿cómo pongo una instancia única de una cosa en dos listas diferentes? Tendría que usar referencias? Entonces, ¿cómo evito que la lista B itere sobre una lista A que se dice eliminar? Parece que tendría que agregar un booleano "is_deleted_skip_me" en cada estructura (y seleccionarlos periódicamente) o ¿debo seguir limpiando mis listas cada vez que cambie una lista? - EDIT: comienzo a pensar que la aplicación está mal diseñada si necesita tantas listas separadas. – gecko

+0

@gecko: muchas listas interdependientes se ven mal, aunque no conozco sus limitaciones. ¿No puedes copiar la información para que cada lista tenga su propia copia? De lo contrario, siempre existe la posibilidad de utilizar un 'shared_ptr', pero abre la puerta a algunas dificultades en el futuro. –

+0

Cajas (objeto de datos) dentro de un contenedor (en sí mismo una instancia diferente de la misma estructura, solo el nombre y la capacidad difieren), por lo que el contenedor tiene una lista de sus contenidos. Un agente recuerda los últimos N elementos que tocó. Entonces, si un agente coloca cajas en un contenedor, eso significa 2 listas con los mismos elementos. – gecko

Cuestiones relacionadas