Fallo al cargar wntdll.pdb debido a manejo incorrecto de punteros

Problema técnico: Error al intentar cargar wntdll.pdb

El mensaje "No se pudo cargar wntdll.pdb" en Visual Studio generalmente no indica un problema con el entorno de desarrollo, sino un fallo grave en la gestión de memoria del código. Este error suele aparecer cuando se intenta liberar memoria que ya ha sido liberada o que apunta a una región inválida.

A continuación se muestra un ejemplo de código problemático:

#include <iostream>
using namespace std;

class Name {
private:
    char* first;
    char* second;
    char* third;

public:
    Name(string f = "", string s = "", string t = "") {
        first = new char[f.length() + 1];
        second = new char[s.length() + 1];
        third = new char[t.length() + 1];
        strcpy_s(first, f.length() + 1, f.c_str());
        strcpy_s(second, s.length() + 1, s.c_str());
        strcpy_s(third, t.length() + 1, t.c_str());
    }

    // Constructor de copia omitido → uso predeterminado (copia por valor de puntero)
    ~Name() {
        cout << "Destructor llamado\n";
        delete[] first;
        delete[] second;
        delete[] third;
    }

    void Printname() {
        cout << first << " " << second << " " << third << endl;
    }
};

class Person {
private:
    Name n;
    string sex;
    string national;

public:
    Person(Name a, string sex, string national) : n(a), sex(sex), national(national) {
        cout << "Objeto Person creado\n";
    }

    void printName() { n.Printname(); }
    void printNational() { cout << national << endl; }
};

int main() {
    Name name("Billy King", "Bully", "Big X");
    Person person(name, "Male", "Nihonmachi");

    person.printName();
    person.printNational();

    return 0;
}

Este código parece funcional, pero contiene un error crítico: el constructor de copia por defecto realiza una copia de los punteros (first, second, third) sin asignar nueva memoria. Al finalizar la función main, el objeto name es destruido, lo que libera la memoria apuntada por sus miembros. Sin embargo, el objeto person aún mantiene punteros a esa misma memoria, ahora inválida.

Cuando el destructor de Person se ejecuta y llama al destructor de n, se intenta liberar memoria ya liberada, provocando acceso a memoria corrupta y generendo el error de carga de wntdll.pdb.

Solución correcta: Implementar constructor de copia adecuado

#include <iostream>
#include <cstring>
using namespace std;

class Name {
private:
    char* first;
    char* second;
    char* third;

public:
    Name(string f = "", string s = "", string t = "") {
        first = new char[f.length() + 1];
        second = new char[s.length() + 1];
        third = new char[t.length() + 1];
        strcpy_s(first, f.length() + 1, f.c_str());
        strcpy_s(second, s.length() + 1, s.c_str());
        strcpy_s(third, t.length() + 1, t.c_str());
    }

    Name(const Name& other) {
        cout << "Constructor de copia activado\n";

        int len1 = strlen(other.first);
        int len2 = strlen(other.second);
        int len3 = strlen(other.third);

        first = new char[len1 + 1];
        second = new char[len2 + 1];
        third = new char[len3 + 1];

        strcpy_s(first, len1 + 1, other.first);
        strcpy_s(second, len2 + 1, other.second);
        strcpy_s(third, len3 + 1, other.third);
    }

    ~Name() {
        cout << "Destructor ejecutado\n";
        delete[] first;
        delete[] second;
        delete[] third;
    }

    void Printname() {
        cout << first << " " << second << " " << third << endl;
    }
};

class Person {
private:
    Name n;
    string sex;
    string national;

public:
    Person(Name a, string sex, string national) : n(a), sex(sex), national(national) {
        cout << "Persona creada exitosamente\n";
    }

    void printName() { n.Printname(); }
    void printNational() { cout << national << endl; }
};

int main() {
    Name name("Billy King", "Bully", "Big X");
    Person person(name, "Male", "Nihonmachi");

    person.printName();
    person.printNational();

    return 0;
}

Con esta corrección, cada objeto Name tiene su propia copia de los datos, evitando cualquier acceso a memoria inválida.

Recomendación clave: Evita usar char* para cadenas en C++. Prefiere std::string, que gestinoa automáticamente la memoria y previene errores como este. El uso de punteros manuales es propenso a fugas de memoria, dobles libreaciones y accesos a memoria no válida.

Etiquetas: Visual Studio C++ Punteros Memoria Dinámica constructor de copia

Publicado el 9-21 11:47