Pregunta

¿Las cadenas literales que usamos dentro de las funciones son variables automáticas? ¿O están asignados en el montón que tenemos que liberar manualmente?

Tengo una situación como el código que se muestra a continuación en el que asigno un literal de cadena a un campo privado de la clase (marcado como UNO en el código) y lo recupero mucho más tarde en mi programa y lo uso (marcado como DOS). ¿Estoy asignando una variable en la pila a un campo en UNO? ¿Puede el código hacer referencia a un puntero colgante que en este caso funcionó porque el programa era lo suficientemente pequeño?

Lo compilé y lo ejecuté, funcionó bien, pero tengo un bloqueo extraño en mi programa real donde asigno literales de cadena a campos de la clase como este y sospecho del caso que mencioné anteriormente.

#include <iostream>

using namespace std;

class MemoryLeak
{
private:
    char *s;
public:
    MemoryLeak() {}

    void store()
    {
        s = "Storing a string"; // ONE
    }

    char *retrieve()
    {
        return s;
    }
};

int main()
{
    MemoryLeak *obj = new MemoryLeak();
    obj->store();
    cout << obj->retrieve() << endl; // TWO
    delete obj;
    return 0;
}

¿Debo declarar la variable " " como una matriz de caracteres en lugar de un puntero? Estoy planeando usar std :: string, pero tengo curiosidad sobre esto.

Cualquier puntero o ayuda es, como siempre, muy apreciado :) Gracias.

¿Fue útil?

Solución

El compilador colocará los literales de cadena en el segmento de datos o texto (código) inicializado de su binario, en lugar de residir en la memoria (en tiempo de ejecución asignado) o en la pila. Así que deberías usar un puntero, ya que estarás haciendo referencia al literal de cadena que el compilador ya ha producido para ti. Tenga en cuenta que si modifica esto (lo que normalmente requeriría cambiar la protección de la memoria) cambiará todos los usos de este literal.

Otros consejos

Es un comportamiento indefinido modificar un literal de cadena, y es muy probablemente la causa de la falla en su programa (ISO C ++: 2.13.4 / 2). El estándar permite la conversión de un literal de cadena a char * para compatibilidad con versiones anteriores a C y solo debes tener esa conversión en tu código si es absolutamente necesario.

Si desea tratar el literal de cadena como una constante, puede cambiar el tipo de su miembro a un const char * .

Si su diseño requiere que se modifique s , entonces recomendaría cambiar su tipo a std :: string .

Gracias, Cody y Richard.

He encontrado la causa del error. Fue porque estaba haciendo una eliminación en un objeto que ya estaba eliminado. Yo estaba haciendo:

if (obj != NULL) delete obj;

Lo cambié a:

if (obj != NULL)
{
    delete obj;
    obj = NULL;
}

Aprender C ++ es definitivamente divertido :)

¿Quizás la causa del bloqueo es que no finalizó la cadena con un 0?

Veamos sus opciones.
También hay un par de cosas que debes hacer:

    /*
     * Should initialize s to NULL or a valid string in constructor */
        MemoryLeak()
        {
            store();
        }

        void store()
        {
            // This does not need to be freed because it is a string literal
            // generated by the compiler.
            s = "Storing a string"; // ONE

            // Note this is allowed for backward compatibility but the string is
            // really stored as a const char* and thus unmodifiable. If somebody
            // retrieves this C-String and tries to change any of the contents the
            // code could potentially crash as this is UNDEFINED Behavior.

            // The following does need to be free'd.
            // But given the type of s is char* this is more correct.
            s = strdup("Storing a string");

            // This makes a copy of the string on the heap.
            // Because you allocated the memory it is modifiable by anybody
            // retrieving it but you also need to explicitly de-allocate it
            // with free()
        }

Lo que estás haciendo es usar C-Strings. Estos no deben confundirse con C ++ std :: string. C ++ std :: string se inicializa automáticamente en la cadena vacía. Cualquier memoria asignada se desasigna correctamente. Se puede devolver fácilmente como una versión modificable y no modificable. También es fácil de manipular ( es decir, aumentar el tamaño del cambio). Si creces un C-String, necesitas reasignar la memoria y copiar la cadena en la nueva memoria, etc. (es muy probable que exista un error).

Para hacer frente a la asignación dinámica de su objeto, aprendería sobre punteros inteligentes. Consulte este artículo para obtener más detalles sobre los punteros inteligentes.
Smart Pointers o quién es su dueño, Baby

std::auto_ptr<MemoryLeak> obj(new MemoryLeak());

obj->store();
std::cout << obj->retrieve() << std::endl; // TWO

// No need to delete When object goes out of scope it auto deletes the memory.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top