Должен ли я ТОЛЬКО беспокоиться о новых и сопоставлять их с удалениями? - PullRequest
0 голосов
/ 03 ноября 2010

У меня есть код C ++, в котором у меня есть несколько типов данных. Главное, у меня есть класс:

class coordinate{
    int x, y;
    public:
     void set_values(int, int);
}

Тогда я мог бы сказать:

coordinate* origin = new coordinate;

Очевидно, что для восстановления памяти, выделенной для источника, я бы наконец сказал:

delete(origin);

Пока все хорошо ...

У меня вопрос, есть ли другие типы данных, удаление / уничтожение которых Я ДОЛЖЕН АБСОЛЮТНО РУЧНО позаботиться о предотвращении утечки памяти?

Другие типы данных:

string (объект этого типа данных имеет функцию end ()), stringstream, char [].

Например, У меня есть функция setname (), которая вызывается из main () несколько раз, что делает это:

void setname(){

    for(int k = 0; k < 10; k++){
        string NAME = "Point ";
        stringstream s;
        s << k;
        NAME += s.str();
        char name[7];
        strcpy(name,NAME.c_str());
        /*  some other stuff... */
        NAME.end(); //<--------------is stuff like this really needed?
//will memory held by NAME, s and name be automatically released as k increments?
    }
}   

Ответы [ 7 ]

4 голосов
/ 03 ноября 2010

Каждый new должен соответствовать delete, каждый new [] - delete [] и каждый malloc - free (но не используйте их в C ++ ...)

3 голосов
/ 03 ноября 2010

Решение вашей проблемы: RAII .

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

2 голосов
/ 03 ноября 2010

Как правило: Если вы new это, delete это. Если вы new[] это, delete[] это. Если вы malloc() это, free() это.

В противном случае вам обычно не нужно ничего делать. (Системные вещи, такие как GlobalAlloc() в Windows или CFStringCreate() в Mac OS X / iOS, имеют свои собственные правила. Информацию об этих системных API-интерфейсах см. В руководстве / FAQ / MSDN.)

1 голос
/ 03 ноября 2010

Ответ: это зависит.Если ваш код выделяет что-либо (string, экземпляр класса coordinate, stringstream и т. Д.) С new, некоторый код (может быть, ваш) должен delete.В противном случае, если вы создаете строку в стеке и передаете ее с помощью конструкторов копирования, вам не нужно ее удалять.

И: NAME.end() вообще не требуется.Функция end() на самом деле возвращает итератор, указывающий за конец строки;это не делает никакой очистки.Так что в вашем коде звонок на end() не нужен.

0 голосов
/ 03 ноября 2010

Нет, нет, нет. Для этого вы используете RAII - он безопасен для исключений.

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

Это означает, что вам никогда не нужно освобождать память, созданную пользовательским типом - она ​​должна освобождаться сама. Вам не нужно будет освобождать память, выделенную ни std :: string, ни std :: stringstream. std :: string :: end () об окончании итерации. Как правило, для любых ресурсов, требующих пользовательского освобождения, вы оборачиваете их в пользовательский тип, чтобы они больше не требовали ручного освобождения.

Для пользовательских типов, выделенных с помощью new, вы можете использовать auto_ptr, который немедленно уничтожает объект, когда он выходит из области видимости и освобождает память, или вы можете использовать shared_ptr, который «разделяет» объект между всеми экземплярами, которые указывают на него с помощью магии. Существуют другие типы интеллектуальных указателей, и для любого конкретного ресурса вы можете написать свой собственный тип управления. Это значительно повышает безопасность вашей программы без потери производительности.

Кроме того, вы никогда и никогда не должны использовать char * или любые другие связанные типы (char [] и т. Д.) Для хранения строк в C ++. Используйте std :: string. Ваш текущий код не поддерживается, так как он умрет или может вызвать случайные ошибки, если вам нужно более 7 символов. Строковые функции в стиле C (strcpy) также крайне устарели и не должны использоваться.

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

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

0 голосов
/ 03 ноября 2010

Используйте C ++ 0x / TR1 shared_ptr <>, если можете, они просто потрясающие, некоторые говорят, что это влияет на производительность, но все же, подумайте о других альтернативах, только если профилировщик жалуется на shared_ptr. Общие указатели являются потокобезопасными и с очень хорошим поведением при переназначении (shared_ptr <> :: reset разделит ссылки).

Единственное, на что вы должны обращать внимание, это new против new [], поэтому мне гораздо больше нравятся распределители памяти типа c (calloc, malloc, free), если мне не нужны конструкторы и деструкторы (то есть типы POD). ).

Для распределителя типа c вы должны использовать: shared_ptr<char> charptr((char*)calloc(10, sizof(char)), free);

P.S .: Для других объектов, следите за дескрипторами ядра и объектами GDI (по крайней мере, в окнах), они не точно пропускают память в классическом смысле, но должны быть закрыты.

Кроме того, функции типа c часто возвращают указатели malloc'd.

0 голосов
/ 03 ноября 2010

Вы всегда можете исследовать boost :: shared_ptr .Вы все еще должны сделать 'new', но удаление обрабатывается внутренне совместно используемым ptr.

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