2015-10-08 7 views
0

Предположим, у меня есть два класса с именем classA и classB. Я создаю указатель на CLASSA, а затем динамически выделить один объект с помощью нового оператора следующим образом:оператор удаления с цепным динамическим распределением

classA *ptrA = new classA

CLASSA имеет элемент типа указателя на ClassB, и в его конструктор по умолчанию выделяет массив объекты типа ClassB в куче следующим образом:

memberOfA = new classB[10]

и усложнить ситуацию, ClassB имеет переменную-член типа INT *, а в его конструктор по умолчанию это allcoates массив целочисленных в куче, как следует:

memberOfB = new int[100]

Теперь, если я называю удалить на PTRA с помощью delete ptrA, как будет компилятор идти о deallocating память, выделенную memberOfA и memberOfB.

+2

Это не будет; Это ваша работа в деструкторах :) Это одна из главных причин популярности виртуальных машин с сборкой мусора, такой как Java и .NET. – racraman

+0

Yeap, а затем вы превысите лимит накладных расходов GC, и вы находитесь в недействительном состоянии, вернитесь к основам! – g24l

+0

Это не будет; не из-за недостающих деструкторов, а потому, что вы используете ** raw указатели ** для _manage_ памяти. – emlai

ответ

1

memberOfA и memberOfB освобождается только если поставить delete[] в destrutors из classA и classB. Так что, если бы вы написали деструктор classA так, чтобы он освободил память, на которую указует memberOfA, как это:

classA::~classA() { 
    delete [] memberOfA; 
} 

В этом случае деструктор освободит массив призывающего деструкторы элементов указываемых записей в memberOfA , То же самое можно сказать и о деструктор classB:

classB::~classB() { 
    delete [] memberOfB; 
} 

Помните, используя new должны быть в паре с последующим delete в какой-то момент, если не вы посмотрите на утечки. Возможно, вам стоит рассмотреть один из классов интеллектуальных указателей: unique_ptr и shared_ptr.

Если конструкция позволяет classA и classB использовать unique_ptr или shared_ptr в массив, большая часть опасностей утечки были бы преодолены:

std::unique_ptr<classB[]> memberOfA(new classB[10]); 

Если порядок удаления представляет интерес для вас тогда вызов delete ptrA приведет к вызову деструктора classA, и если мы предположим, что он реализован как намеченный выше (с использованием delete []), то оператор delete [] вызовет деструкторы всех членов в порядке убывания адреса, из Стандарта, проект N3690, § 5.3.5/6:

Если значение операнда удаления-выражения не нулевое значение указателя, удаления выражение будет вызывать деструктор (если таковые имеются) для объекта или элементы массива удаляется , В случае массива элементы будут уничтожены в порядке убывания адреса (то есть в обратном порядке завершения их конструктора, см. 12.6.2).

Это, конечно, приводят к деструктору classB вызывается для каждого элемента, который будет снова использовать delete [] memberOfB, который будет освободить массив, указывающий на целые числа.

2

Теперь, если я называю удалить на PTRA с помощью delete ptrA, как будет компилятор идти о deallocating память, выделенную memberOfA и memberOfB.

При вызове delete ptrA, компилятор будет вызывать деструктор classA. Если этот деструктор не delete [] memberOfA, тогда вы просачиваетесь как memberOfA, так и, следовательно, memberOfB.

Если вместо ручного управления памятью (new и delete) вы использовали автоматическое управление памятью (SBRM/RAII), вам не нужно было бы писать никаких деструкторов, и выделенные вами ресурсы были бы освобождены, как ожидалось, например:

std::unique_ptr<classA> ptrA(new classA); 
std::unique_ptr<classB[]> memberOfA(new classB[10]); 
std::unique_ptr<int[]> memberOfB(new int[100]); 

Это на самом деле современный C++ способ сделать это. Код становится понятнее, поскольку семантика собственности указателей написана в их типе, и нет деструкторов, лежащих вокруг. Еще лучший способ - использовать std::make_unique(...) вместо new, но я оставил его для простоты.

+1

Yup, не используйте необработанные указатели для управления памятью в эти дни, если вы не сумасшедшие – paulm

+0

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

1

Это не ... вы должны сделать это, внедряя деструктор! Вы можете сделать это, используя оператор delete [].

classA::~classA() { 
    delete [] memberOfA; 
} 

и

classB::~classB() { 
    delete [] memberOfB; 
} 

, а затем вы удалите PTRA порядок выполнения будет:

call classA::~classA() 
call classB::~classB() on each of the elements of memberOfA 
deallocate memory for the array of ints pointed by memberofB 
deallocate memory for the array of memberofA 
deallocate memory for classA 

Deallocation памяти может произойти на самом деле на более поздних стадиях в некоторых случаях.

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

class classB 
{ 
... 
std::array<int,100> memberOfB; 
... 
}; 
class classA 
{ 
... 
std::array<classB,10> memberOfA; 
... 
}; 

std::unique_ptr<A> ptrA(new classA) 
Смежные вопросы