1

У меня, похоже, проблема с распределением динамической памяти.C++: Развертывание динамической памяти, когда объект производного класса разрушен

Ниже вы увидите производный класс, содержащий указатель на переменную имени, которая будет динамически распределяться с использованием метода void name(const char* name). Функция запускается конструктором Product, который задает имя для класса продукта при создании объекта. Вот класс:

namespace sict { 
    class Product :public Streamable { 

    char* name_; 

public: 

    Product(const char* name); 
    virtual ~Product(); 

    void name(const char* name); 

} 

А вот само имя функции, наряду с конструктором один аргумент:

void sict::Product::name(const char * name) { 
    int g = strlen(name); 
    name_ = new char[g]; 
    strncpy(name_, name, g); 
    name_[g] = 0; 
} 

Product::~Product() { 
    delete [] name_; 
    name_ = nullptr; 
} 

Для меня этот код кажется способным достаточно создаваемого объекта затем уничтожить его мирно, когда он выходит объем выполняемой функции. Однако, когда функция заканчивается и деструктор работает, программа зависает/падает на delete [] name_. Запуск программы в компиляторе Visual Studio, похоже, не дает особых ошибок (кроме замораживания программы), но компилятор gcc обнаруживает какое-то кучное повреждение. Кто-нибудь знает, почему это происходит?

+6

'name_ [г] = 0;' списывает конца выделенного массива, повреждать кучу. Попробуйте изменить 'g' на' strlen (name) + 1' для подтверждения. Поскольку это C++, вам будет намного лучше использовать ['std :: string'] (http://en.cppreference.com/w/cpp/string/basic_string) и позволить ему обрабатывать управление памятью для вас. –

+3

Вы не придерживаетесь [Правило 3] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). – PaulMcKenzie

+4

О, это просто, просто используйте 'std :: string'. Знаете, это C++. Not C. –

ответ

3

Я не уверен, почему Шон Клайн не опубликовал свой комментарий в качестве ответа, но Шон прав.

name_ содержит g элементов, а затем name_[g] установлен на ноль, но name_[g] - один за конец массива. Используйте либо name_ = new char[g+1];, либо name_[g-1] = 0;, чтобы вы не проходили мимо конца массива.

Кроме того, как несколько замечаний указывают, в любое время у вас есть класс, который выделяет память динамически, убедитесь, что вы определили конструктор копирования, оператор в назначения, а деструктор. Если вы пропустите один, реализация по умолчанию будет выполнять мелкой копии, которая может вызвать головную боль для вас.

A мелкая копия - это когда указатель скопирован вместо данных, на которые он указывает. В вашем случае, если объект этого класса когда-либо копируется или назначается, вы получаете два объекта, указывающих на одни и те же данные в куче, и оба они попытаются удалить его при запуске своих деструкторов.

Для получения более подробной информации об этих функциях см Rule of Three