Последовательный новый и удалить - PullRequest
4 голосов
/ 19 июля 2011

В продолжение моего предыдущего вопроса я хотел бы спросить следующее:

Учитывая функцию C ++, имеющую новый оператор в ней, но не возвращающую ничего явно (т.е. с возвратомзаявление), следует ли также удалить всегда?

Если нет, не могли бы вы привести пример.

Ответы [ 7 ]

4 голосов
/ 19 июля 2011

Правило с новым очень простое: указатель, возвращаемый new, должен быть удален в какой-то момент кем-то , где-то в коде.Если указатель, возвращаемый new, потерян, забыт или отброшен, то у вас есть утечка памяти, и это плохо.

Поэтому, если вы new увеличите объем памяти и вернетесь, не сохраняя ее где-либонавсегда, значит у тебя утечка памяти.Следовательно, если вы не собираетесь его удалять, указатель должен быть либо сохранен в каком-либо долговременном хранилище (член класса, статической переменной и т. Д.), Либо возвращен, чтобы кто-то другой мог его удалить..

Кроме того, вы можете просто использовать boost :: shared_ptr и прекратить заботиться об этом (большей части).

4 голосов
/ 19 июля 2011

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

  • В функции-члене создайте объект и назначьте его полю содержащего объекта.

Пример:

class Foo {
    private:
        Baz* baz;
    public:
        Foo() : baz(0) { }
        void create_bar() { baz = new Baz(); }
        ~Foo() { delete baz; }
};
  • Передача нового объекта чему-то другому.

Примеры:

void foo() {
    // assuming bar lives in the global scope
    bar.baz = new Baz();
}

void foo2(Bar& bar) {
    bar.baz = new Baz();
    // or, better:
    bar.setBaz(new Baz());
}
  • Использование какого-либо типа указателя для сбора мусора.

Пример: * * один тысяча двадцать-одна

std::auto_ptr<Baz> foo() {
    return new Baz();
}
  • Передача указателя в другую функцию, которая что-то делает с ней, а затем удаляет ее.

Пример: * * тысяча двадцать-восемь

void foo(Bar* bar) {
    bar->dostuff();
    delete bar;
}

void baz() {
    Bar* bar = new Bar();
    foo(bar);
}
1 голос
/ 19 июля 2011

Если вы выделяете память с помощью new в функции, и эта память не доступна вне функции (или статической), то ее нужно будет освободить до того, как функция будет существовать. В этом случае я бы порекомендовал использовать std::auto_ptr или boost::scoped_ptr, так как он вызовет delete для вас при выходе из функции. Даже если исключения брошены.

1 голос
/ 19 июля 2011

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

void AddProjectileAtPoint(int x, int y)
{
    Projectile *p = new Projectile(x, y);
    mProjectileManager->Add(p); //"mProjectileManager"'s job is to hold all projectiles and update them every frame...
}

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

Очевидно, что в некоторой точке должно быть совпадение delete , но не внутри функции, в которой происходит new. Это нормально, если есть четко определенная процедура передачи ответственности за управление new 'd памятью другому компоненту.

В этом случае структура такова, что «Менеджер снарядов» берет на себя ответственность за все выданные ему снаряды, сохраняет их живыми столько, сколько требуется, и очищает память, когда это необходимо.

1 голос
/ 19 июля 2011

Если функция создает ресурс с использованием new и не передает указатель на этот ресурс обратно, то да, она должна удалить ресурс, иначе она никогда не будет очищена, что приведет к утечке памяти.

0 голосов
/ 19 июля 2011

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

A* ptr = NULL;

void foo() {
   ptr = new A();
}

Вы должны иметь где-то delete ptr, но это не обязательно должно быть в foo().

С другой стороны, если вы не сохранили его где-либо еще:

void foo() {
   A* ptr = new A();
}

Тогда, да, это утечка памяти.Вы никогда не сможете вернуться к этому указателю, чтобы выполнить delete ptr!


Обратите внимание, что лучше использовать некоторую реализацию "умного указателя", такую ​​как shared_ptr или unique_ptr, чтобы справиться с этим.

0 голосов
/ 19 июля 2011

Не обязательно, если он выделяет статический объект (например, для реализации шаблона Singleton).

...