Утечка памяти в C++ (valgrind)

Вальгринд утверждает, что я косвенно теряю память; что меня раздражает, так это то, что я понятия не имею, почему это так.

Не уверен, является ли это ложным срабатыванием или я просто не понимаю какое-либо назначение указателя или что-то в этом роде.

Я теряю память здесь? Если так, то почему?

Отчет Valgrind:

==24392== 21 bytes in 2 blocks are indirectly lost in loss record 1 of 3
==24392==    at 0x4028699: operator new[](unsigned int) (in        /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==24392==    by 0x804B41D: Perishable::load(std::basic_fstream<char,        std::char_traits<char> >&) (Perishable.cpp:42)
==24392==    by 0x804C504: sict::PosApp::loadRecs() (PosApp.cpp:139)
==24392==    by 0x804D58E: sict::PosApp::run() (PosApp.cpp:393)
==24392==    by 0x8049337: main (milestone4.cpp:8)

Вот строка 42:

std::fstream& Perishable::load(std::fstream& stream) {
    char    mysku[MAX_SKU_LEN + 1];
    char    mynam[100];
    bool    mytax;
    double  myprice;
    int     myqty;
    int     date[5]; 

    stream.getline(mysku, 100, ',');
    sku(mysku);
    stream.getline(mynam, 100, ',');

    name(mynam);//bytes indirectly lost

Вот имя () [полностью прокомментировано]

void Item::name(char *name){
    delete[] _name; //..............Just in case it points to something.
                    //..............Note: How could I possibly be losing memory with this line here??
    int x = strlen(name); //........Grab the length of the new input

    if (_name == '\0') {//..........If it was empty, ie. its the first assignment
        _name = new char[x + 1];//..Allocate the space, +1 for null char
    }

    for (int i = 0; i < x; i++) {//.Copy
        _name[i] = name[i];
    }

    _name[x]   = '\0';//............Yeah, its manual termination. I should maybe use strcpy
}

Редактировать >>> вот деструктор

Item::~Item() {
    std::cout << "called destructor";
    delete[] _name;
    _name = '\0';
}

Редактировать >> Копировать конструктор и оператор присваивания

//Copy Constructor
Item::Item(const Item& copyfrom){
    (*this) = copyfrom;

}

//Member operators
Item& Item::operator=(const Item &myitem) {
    if (!myitem.isEmpty()){
        init((*this), myitem._sku, myitem._name, myitem._price, myitem._taxed);
        this->_quantity = myitem._quantity;

    }
    return (*this);
}

void Item::init(Item &obj, char const sku[], char const name[], double priced, bool taxed) {

    int length = strlen(name);
    int skulength = strlen(sku);

    obj._price = priced;
    obj._taxed = taxed;
    obj._quantity = 0;
    obj._name = new char[length+1]; //+1 for the null which wasn't counted. Huge pain debugging that.


    for (int i = 0; i < length; i++) {

        obj._name[i] = name[i];

        if (i < skulength) {//redundanc


            obj._sku[i] = sku[i];
        }
    }

    obj._name[length]   = '\0';
    obj._sku[skulength] = '\0';

}

2 ответа

Решение

Я вижу только

Item::~Item() {
    std::cout << "called destructor";
    delete[] _name;
    // Don't reassign
}

а также

void Item::init(Item &obj, char const sku[], char const name[], double priced, bool taxed) {
    // ...
    if (obj._name == nullptr /* 0 */) {
        obj._name = new char[length+1]; 
        // What if it's not null?
    } else {
        // Do you want to delete and new up a char?
    }
}

Кроме того, использование неконстантной ссылки для меня страшно. Я считаю, что обновление obj._name в init является самой большой проблемой, без каких-либо упреждающих проверок.

Если вы действительно должны использовать new и голые указатели (подсказка: почти никто не делает), то вам нужно убедиться, что владелец _name выпускает его, когда он больше не нужен.

Правильное место для этого, вероятно, ~Item() деструктор, но трудно быть уверенным без остальной части вашего кода.

Другие вопросы по тегам