Очистка динамического массива объектов в C ++ - PullRequest
1 голос
/ 20 марта 2010

Я немного озадачен обработкой массива объектов в C ++, так как не могу найти информацию о том, как они передаются (ссылка или значение) и как они хранятся в массиве.

Я ожидал бы, что массив объектов будет массивом указателей на этот тип объекта, но я нигде не нашел этого написанного. Будут ли они указателями или сами объекты будут размещены в памяти в массиве?

В приведенном ниже примере пользовательский класс myClass содержит строку (будет ли она иметь переменный размер, или объект строки будет содержать указатель на строку и, следовательно, занимать постоянное количество места. Я пытаюсь создать динамический массив объектов myClass в myContainer. В методе myContainer.addObject () я пытаюсь создать массив большего размера, скопировать все объекты в него вместе с новым объектом, а затем удалить старый. Я не совсем уверен что я правильно очищаю свою память своими деструкторами - какие улучшения я могу сделать в этой области?

class myClass
{
    private:
          string myName;
          unsigned short myAmount;

    public:
        myClass(string name, unsigned short amount)
        {
            myName = name;
        myAmount = amount;
        }

    //Do I need a destructor here? I don't think so because I don't do any
    // dynamic memory allocation within this class
};



class myContainer
{
    int numObjects;
    myClass * myObjects;

   public:
    myContainer()
    {
        numObjects = 0;
    }   

    ~myContainer()
    {
        //Is this sufficient?
        //Or do I need to iterate through myObjects and delete each
        // individually?
        delete [] myObjects;
    }


    void addObject(string name, unsigned short amount)
    {
        myClass newObject = new myClass(name, amount);

        myClass * tempObjects;
        tempObjects = new myClass[numObjects+1];
        for (int i=0; i<numObjects; i++)
            tempObjects[i] = myObjects[i]);
        tempObjects[numObjects] = newObject;
        numObjects++;
        delete newObject;

        //Will this delete all my objects? I think it won't.
        //I'm just trying to delete the old array, and have the new array hold
        // all the objects plus the new object.
        delete [] myObjects;
        myObjects = tempObjects;
    }
};

Ответы [ 4 ]

3 голосов
/ 20 марта 2010

Массив в C ++ - это массив объектов, расположенных в памяти. Так, например, в:

struct pair {
   int x; int y;
};
...
pair array[10];

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

pair* array_of_pointers[10];

Строковые объекты имеют указатели на часть строки переменного размера. Так что они в безопасности. На самом деле они важный урок здесь. Так же, как вы используете строковый класс, чтобы избежать чрезмерной обработки памяти, вы можете использовать векторный класс, чтобы избежать всех проблем с обработкой динамического массива.

Для случая, когда вы делаете это как упражнение. Вот несколько проблем: newObject должен быть выделен локально, без new. Это сделает код правильным (так как newObject не является указателем, а new возвращает указатель), а также избавит вас от необходимости явной обработки памяти. (На более сложной ноте это делает исключение кода безопасным в еще одном месте) myObject никогда не инициализируется. И вы не используете списки инициализации в конструкторе. Конструктор должен выглядеть так:

myContainer() : numObjects(0), myObjects(NULL)
{

}  

Деструкторы в коде точно такие, какими они должны быть.

3 голосов
/ 20 марта 2010

Нет, динамический массив не является массивом указателей на этот тип - это указатель на первый элемент. Элементы располагаются последовательно в памяти и уничтожаются, когда массив равен delete[] ed.

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

Есть две явные ошибки:

tempObjects[numObjects] = newObject; // assign a myClass pointer to a myClass instance?

Это должно быть, например ::

tempObjects[numObjects] = myClass(name, amount);

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

Наконец, если вы не делаете это в учебных целях, просто используйте контейнеры, подобные std::vector, которые уже выполняют всю работу за вас.

1 голос
/ 20 марта 2010

Я ожидал бы, что массив объектов будет массивом указателей на этот тип объекта, но я нигде не нашел этого написанного. Будут ли они указателями или сами объекты будут размещены в памяти в массиве?

Массив будет состоять из самих объектов. Если вы хотите иметь массив указателей, вам придется объявить, что:

myClass ** tempObjects;  
tempObjects = new myClass*[numObjects+1];  

Полагаю, вы привыкли к C # или Java? В этих языках объекты могут быть размещены только в куче и всегда доступны по ссылке. Это возможно в C ++, но в C ++ вы также можете помещать объекты непосредственно в стек или напрямую создавать массив самих объектов.

В приведенном ниже примере пользовательский класс myClass содержит строку (будет ли он иметь переменный размер, или объект строки будет содержать указатель на строку и, следовательно, занимать согласованное количество места?

Номер два: сам строковый объект имеет постоянный размер, но имеет указатель на буфер динамического размера, выделенный из кучи.

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

0 голосов
/ 20 марта 2010

Попробуйте проверить это, чтобы увидеть, что происходит (да, это может зависеть от компилятора, но все же) ... Вы можете попытаться добавить пользовательский деструктор в myClass (даже если он вам не нужен), который увеличивает "глобальный" счетчик при вызове, а затем распечатывает счетчик после удаления массива.

Я ожидаю, что деструктор каждого объекта будет вызван. Обратите внимание, что довольно часто объекты хранятся «побочными указателями», что позволяет помещать унаследованные объекты в массив (избегая «нарезки»).

...