2011-01-17 2 views
4

Исходя из фона C#, у меня есть только самая неопределенная идея по управлению памятью на C++ - все, что я знаю, это то, что мне придется освобождать память вручную. В результате мой код на C++ написан таким образом, что объекты типа std::vector, std::list, std::map свободно создаются, используются, но не освобождаются.Свободная память, занимаемая Std List, Vector, Map и т. Д.

я не понимал эту точку, пока я не почти закончили с моими программами, теперь мой код состоит из следующих видов моделей:

struct Point_2 
{ 
    double x; 
    double y; 
}; 

struct Point_3 
{ 
    double x; 
    double y; 
    double z; 
}; 

list<list<Point_2>> Computation::ComputationJob 
    (list<Point_3>pts3D, vector<Point_2>vectors) 
{ 
    map<Point_2, double> pt2DMap=ConstructPointMap(pts3D); 
    vector<Point_2> vectorList = ConstructVectors(vectors); 
    list<list<Point_2>> faceList2D=ConstructPoints(vectorList , pt2DMap); 
    return faceList2D; 
} 

Мой вопрос, я должен освободить каждый. single.one Использование списка (в приведенном выше примере это означает, что мне нужно было бы освободить pt2DMap, vectorList и faceList2D)? Это было бы очень утомительно! Я мог бы просто переписать мой класс Computation, чтобы он был менее подвержен утечке памяти.

Любая идея, как исправить это?

+2

На самом деле лучше использовать ссылки в параметрах метода. Копирование неэффективно. – ssmir

+0

@ssmir, старые привычки в C# умереть! – Graviton

ответ

10

Нет: если объекты не выделены new, они не должны быть явно освобождены/удалены. Когда они выходят из сферы действия, они автоматически освобождаются. Когда это происходит, вызывается деструктор, который должен освобождать все объекты, к которым они относятся. (Это называется Resource Acquisition Is Initialization, or RAII, и стандартные классы, такие как std::list и std::vector следовать этому образцу.)

Если вы используете new, то вы должны либо использовать смарт-указатель (scoped_ptr) или явный вызов delete. Лучшее место для звонка delete находится в деструкторе (по соображениям безопасности исключений), хотя интеллектуальные указатели должны быть по возможности предпочтительными.

+0

@larsmans, так что вы говорите, что мне не нужно разбираться с освобождением памяти для 'std :: list' и всего? – Graviton

+0

Из-за всего копирования существуют некоторые ситуации, когда простой RAII может быть катастрофой в сочетании с контейнерами C++. –

+0

Только если вы, как T.E.D. говорит, используйте 'new' в' class Point_2', вам нужно беспокоиться о распределении и освобождении. Стандартные контейнеры обрабатывают распределение памяти внутри. (Читайте об RAII, полезно избегать трудностей ручного управления памятью.) –

2

В общем, я могу сказать, что стандартные контейнеры C++ делают копии вашего объекта под сценой. У вас нет контроля над этим. Это означает, что если построение ваших объектов (Point_2 в вашем случае) включает в себя любые распределения ресурсов (например: new или malloc звонки), тогда вам нужно написать собственные версии конструкторов и деструкторов копирования, которые заставляют это вести себя разумно, когда ваша карта решает скопировать Point_2 с. Обычно это включает в себя такие методы, как подсчет ссылок.

Многим людям гораздо проще просто поставить указатели на сложный объект в стандартные контейнеры, а не на сами объекты.

Если вы не делаете ничего особенного в конструкторах или деструкторах для ваших объектов (что теперь кажется вам случайным), нет никаких проблем. Некоторые контейнеры (например, карты) будут делать динамические выделения под сценами, но это вам фактически невидимо. Контейнеры беспокоятся об их распределении ресурсов. Тебе нужно только беспокоиться о твоем.

+1

вопрос обновлен. Не слишком уверенно, что вы имеете в виду, мне не нужно использовать 'new' или' malloc' для выделения памяти как для «Point_2», так и «Point_3», как показано в приведенном выше коде, поэтому я предполагаю, что это означает, t нужен какой-либо пользовательский код для управления памятью. – Graviton

+0

Согласен. С помощью тех, которые (часто называемые ** POD ** s или простые старые типы данных), вы можете использовать контейнеры STL с откатом, не беспокоясь о динамических распределениях. –

0

Все контейнеры stl автоматически очищают свое содержимое, все, что вам нужно, это очистка данных, которые вы распределяете динамически (т. Е. Правило: позаботьтесь о указателях).

Например, если у вас есть list<MyType> - список содержит объекты некоторого пользовательского типа внутри - на опустошение он будет вызывать ~MyType(), которые должны заботиться о надлежащей очистки содержимого объекта (т.е. если MyType имеет некоторые указатели на выделенную память внутри , вы должны удалить их в деструкторе).

С другой стороны, если вы начинаете использовать list<MyType*> - контейнер теперь очищает его правильно, он содержит некоторые скалярные значения (как целые числа) и удаляет только указатели самостоятельно, не очищая заостренный контент, поэтому вам нужно для очистки этого вручную.

Действительно хороший совет (помог мне много лет назад :)) при переходе с Java/C# на C++ - тщательно отслеживать жизненный цикл объекта динамической памяти: a) где он создается, b) где он используется, c) где и когда он удаляется. Удостоверьтесь, что он очищается только один раз и после этого не получает ссылки!

+0

Отредактировано «std» на «stl», поскольку STD имеет некоторые другие неудачные коннотации на английском языке. Вернитесь, если хотите. Я согласен с тем, что если все std-контейнеры автоматически очистят свое содержимое, мир станет намного лучше. :-) –

Смежные вопросы