Что мне нужно знать о памяти в C ++? - PullRequest
16 голосов
/ 15 декабря 2009

Я делал все возможное, чтобы выучить C ++, но мое предыдущее обучение не дотягивает до одной важной проблемы: управления памятью. Все мои основные языки имеют автоматическую сборку мусора, поэтому отслеживать все на самом деле никогда не было необходимости. Я пытался прочитать об управлении памятью в C ++ онлайн, но у меня есть это потрясающее подозрение, что я что-то упускаю.

Итак, вот вопрос из нескольких частей:

  • Какой минимум мне нужно знать об управлении памятью? (или где я могу это выяснить)?
  • Куда мне обращаться за промежуточными и продвинутыми знаниями / учебными пособиями / и т. д. (как только я закончу с основами)?
  • В чем разница в производительности между указателями и ссылками?
  • Я слышал, что в циклах необходимо убедиться, что вы вызываете delete для любых новых указателей, прежде чем цикл будет повторяться , Это правильно? Вам нужно что-то сделать со ссылками?
  • Какие есть классические примеры утечек памяти?
  • Что мне нужно знать о следующем (и буду ли я когда-либо реально использовать их - - если да, то где?)
    • malloc
    • free
    • calloc
    • realloc

*********************** ОБНОВЛЕНИЕ *******************

Это относится к ссылке на lmgtfy в первом комментарии (автор Ewan). Если вы начинаете читать информацию, которая доступна там, это не полезно для новичка. Я думаю, что это великая теория, но она не является ни уместной, ни полезной для этого вопроса.

Ответы [ 15 ]

24 голосов
/ 15 декабря 2009

Вы действительно, действительно должны прочитать хорошую книгу - откровенно изучение C ++ невозможно без нее. Я рекомендую Ускоренный C ++ от Koenig & Moo, двух создателей C ++.

15 голосов
/ 15 декабря 2009

Управление памятью

Основы

  • Каждое «использование» new должно совпадать с «использованием» delete
  • Массив new отличается от обычного new и имеет свое собственное удаление

_

 int*  data1 = new int(5);
 delete data1;

 int*  data2 = new int[5];
 delete [] data2;

должен знать

  • Исключения
  • RAII
  • Правило 4.

исключение из деструктора
Динамическое выделение массива объектов Имя шаблона для создания в конструкторе, удаления в деструкторе (C ++)

Лучшая практика

  • Никогда не используйте RAW-указатели.
  • Всегда заключайте указатели в Smart Pointers.
  • Изучите различные типы умных указателей и когда использовать каждый

Умные указатели: или кому принадлежит ваш ребенок?

Дополнительно:

  • Понимание исключительных гарантий
  • Понимание использования броска

Какими принципами руководствуется ваша политика обработки исключений?

Распространенные способы утечки

Основы

// Every new is matched by a delete.
for(int loop = 0;loop < 10;++loop)
{
    data = new int(5);
}
delete data;
// The problem is that every 'use of' new is not matched by a delete.
// Here we allocate 10 integers but only release the last one.

должен знать

class MyArray
{
    // Use RAII to manage the dynamic array in an exception safe manor.
    public:
        MyArray(int size)
          :data( new int[size])
        {}
        ~MyArray()
        {
            delete [] data;
        }
    // PROBLEM:
    // Ignored the rule of 4.
    // The compiler will generate a copy constructor and assignment operator.
    // These default compiler generated methods just copy the pointer. This will
    // lead to double deletes on the memory.

    private:
        int*   data;
};

Лучшая практика

// Understand what the properties of the smart pointers are:
//
std::vector<std::auto_ptr<int> >   data;

// Will not work. You can't put auto_ptr into a standard container.
// This is because it uses move semantics not copy semantics.

Дополнительно:

// Gurantee that exceptions don't screw up your object:
//
class MyArray
{
   // ... As Above: Plus
   void resize(int newSize)
   {
       delete [] data;
       data = new int[newSize];
       // What happens if this new throws (because there is not enough memory)?
       // You have deleted the old data so the old data so it points at invalid memory.
       // The exception will leave the object in a completely invalid state
   }
14 голосов
/ 15 декабря 2009

Что вам нужно знать об управлении памятью в простейшем смысле, так это то, что вам нужно удалить память, выделенную в куче. Поэтому при создании объекта типа MyClass *myClass = new MyClass(x); в вашем коде должно быть место, которое освобождает / удаляет его с соответствующим delete. На практике это кажется простым, но без надлежащего проектирования и использования вспомогательных объектов, таких как общие указатели, это может быстро запутаться, особенно если поддерживать код и добавлять функции. Например вот классическая утечка памяти:

try
{
    MyClass *myClass = new MyClass(x);

    // Do some stuff can throw an exception

    delete myClass;
}
catch(...)
{
   // Memory leak on exceptions.  Delete is never called
}

ИЛИ другая проблема с управлением большой памятью вызывает неправильный тип удаления:

int* set = new int[100];
delete set;   // Incorrect - Undefined behavior
// delete [] set;  is the proper way to delete an array of pointers

Обычный способ помочь себе - использовать идиому RAII. ( Распределение ресурсов - инициализация )

Вот пример использования библиотеки std для предотвращения утечки памяти:

try
{ 
    auto_ptr<MyClass> myClass(new MyClass(x));
    // Now the heap allocated memory associated with myClass
    // will automatically be destroyed when it goes out of scope,
    // but you can use it much like a regular pointer

    myClass->memberFunction();
} 
catch (...)
{

}

Более подробную информацию о auto_ptr можно найти здесь . Если вы можете использовать C ++ 11, shared_ptr - это настоятельно рекомендуемый выбор, который часто предпочтительнее, чем auto_ptr.

5 голосов
/ 15 декабря 2009

Какой минимум мне нужно знать об управлении памятью? (или же, куда я могу это выяснить)?

Для каждого нового должно быть удаление

Куда мне обращаться за промежуточными и продвинутыми знаниями / учебными пособиями / и т. Д. (Как только я закончу> основы)?

Чтение Эффективный C ++ , Более эффективный C ++ и Эффективный STL . Затем Google (std: :) auto_ptr, (boost: :) scoped_ptr и (boost: :) shared_ptr

Более конкретно: в чем разница в производительности между указателями и ссылками?

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

Я слышал, что в циклах вам нужно убедиться, что вы вызываете delete для любых новых указателей, прежде чем цикл будет повторяться. Это правильно?

Да.

Вам нужно что-то сделать со ссылками?

номер

Какие классические примеры утечек памяти?

int * foo() {
...
return new int(...);
}

int main() {
int i = *foo();
...
//the new int() from foo leaks
}

Что мне нужно знать о следующем (и буду ли я когда-либо реально использовать их - если да, то где?):

Прежде всего, вы никогда не должны delete указатель malloc ed и никогда не указывать free указатель, созданный с помощью new. В общем, эти функции не должны появляться в коде c ++. Однако, если вы окажетесь в c-land ...

malloc: аналогично new (выделяет память в куче)
бесплатно: аналогично удалению (свободной памяти в куче)
calloc: аналогично new + memset (выделяет память в куче, устанавливает ее в ноль)
realloc: пытается изменить размер блока памяти или создает новый блок памяти и копирует старые данные, free используя старый указатель. Нет реального эквивалента C ++.

Некоторый аккуратный материал в памяти можно найти с помощью Google (это так пишется?) placement new

5 голосов
/ 15 декабря 2009

Во-первых, вы должны понять концепции стека и кучи .

После вы поймете эти понятия и приступите к изучению языковых конструкций.

4 голосов
/ 15 декабря 2009

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

3 голосов
/ 15 декабря 2009

Книга под названием «Память как концепция программирования на C и C ++» очень хороша для новичков в C / C ++.

2 голосов
/ 15 декабря 2009

В других языках вы уже должны отслеживать соединения с базой данных, дескрипторы окон, сокеты и т. Д. С помощью таких механизмов, как «наконец» (в Java) или «использование» (в C #). В C ++ просто добавьте память в этот список. С концептуальной точки зрения все по-другому.

2 голосов
/ 15 декабря 2009

Ого, это очень много для решения.

Самое главное, чтобы быть последовательно усердным и дисциплинированным. Это верно для любого ресурса на любом языке, даже более безопасного языка управления. Люди чувствуют, что когда язык управляет их памятью, им не нужно об этом думать. Но всегда лучше выпустить любые ресурсы как можно быстрее после того, как вы закончите с ними. Я всегда чувствовал, что "Сборка мусора" делает программистов ленивыми в последние годы.

Всякий раз, когда я выделяю память на языке, подобном с ++, я проверяю, что сначала я освобождаю ее перед использованием. Другими словами, я пишу «выделять», «освобождаю» и затем заполняю середину. Важно войти в постоянную привычку. Я думаю, что это необходимый минимум для изучения ... правильного и дисциплинированного управления ресурсами. Это не только память, она должна применяться ко всем ресурсам, включая ссылки на базы данных, ссылки на файлы, дескрипторы контекста и другие подобные животные.

Весь предмет управления памятью в C ++ довольно обширный. Я бы сказал, читать, изучать и кодировать как можно больше.

пример:

char* myusedmemory;

myusedmemory = (char *)malloc(1000);  // allocate memory

free(myusedmemory);  //  immediately deallocate memory

/*  go back and fill in the code between */

Существует множество хороших ссылок для получения дополнительных знаний по этому вопросу. Я обнаружил, что изучение учебников на relisoft.com было для меня полезным, хотя основное учебное пособие посвящено Windows. Еще одна хорошая ссылка может быть найдена здесь.

Что касается различий между указателями и ссылками, одним из основных отличий является гибкость. Вы должны определить ссылку немедленно (int iExample; int & refExample = iExample;) Я не думаю, что будет большая разница в производительности. Однако указатели, являющиеся более мощными и более гибкими, будут более опасными и потребуют управления вышеупомянутой дисциплиной.

примеры утечек памяти здесь . но вы можете найти больше, прибегая к помощи «утечки памяти в C ++»

Что касается malloc , free , calloc , realloc , это просто функции, как и любые другие команды, в этих В особых случаях функции включены в stdlib. Вы просто должны понимать, что они делают и как их использовать, как и в случае с любыми другими функциями, как и обычная функция printf ().

как примечание: Умные указатели - это очень хороший способ и, как правило, более безопасный.

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

2 голосов
/ 15 декабря 2009

Из вашего списка вы пропустили new и delete - некоторые говорят, что никогда не использовать malloc и free.

Также часто забывают delete[].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...