живот на променлива, създадена чрез динамично заделена памет
Здравейте,
Защо като се излезе от скоуба, да се изтрива copy, нали сме го заделили динамично с ctor-a? Заделена с new памет не живее ли докато решим да я освободим? (примерът е от класа Array)
Array(size_t size) : data(new T[size]), size(size) {}
Array<T>& operator=(const Array<T>& other) {
Array<T> copy(other);
delete[] this->data;
this->data = copy.data;
this->size = copy.size;
return *this;
}
Примерно, ползваме функции за заделяне на динамична и масивът не се изтрива автоматично при излизане от скоуба:
int* allocateMem(int size) {
return new int[size];
}
Поздрави!
1 - nextArr e пойнтър (променлива, която в себе си съдържа адрес на нещо в паметта), който "живее" в стека и просто ще бъде изтрит след като излезе от скоуп. Адреса, към който сочи, няма да бъде модифициран.
2 - Не съвсем. Фокусираш се върху живота на пойнтърите, но не това е важното в случая. Както писах и горе, пойнтърите са само адреси (число) към нещо в паметта. Грижа на програмиста е да осигури правилното менажиране на паметта, сочена от пойнтърите. Дефолтни copy-assignment и copy-constructor биха нарушили правилото на 3-те за тази задача, защото когато бъдат извикани, ще имаме две инстанции, които да сочат към една и съща data в паметта.
copy-assignment примера, който си дала не е дефолтен по своята същност.
Като първа забележка му липсва проверката дали this != &other, смисълът на която е да ни пази от изтриване на паметта, когато напишем myObj = myObj;
Получаваме обекта по референция, правим му копие - ако copy-constructor е дефолтен, то и двете инстанции ще сочат към една и съща data в паметта, после освобождаваме текущата памет и пренасочваме this->data да сочи към същата data като copy (и като other при дефолтен copy-constructor). При излизане от метода ще се извика деструктора на copy, който ще освободи паметта, сочена от copy.data, this->data и other.data (при дефолтен copy-constructor). T.e. - да, остават ни два пойнтъра, които да сочат към оригиналната data, но самата data вече я няма и паметта, към която пойнтърите сочат вече не им принадлежи.
3 - Да, този copy-assignment оператор е коректен
Пост3/СИТ1/ твой отговор: 2 - Не съвсем. (..) "При излизане от метода ще се извика деструктора на copy, който ще освободи паметта, сочена от copy.data, this->data и other.data (при дефолтен copy-constructor). T.e. - да, остават ни два пойнтъра, които да сочат към оригиналната data, но самата data вече я няма и паметта, към която пойнтърите сочат вече не им принадлежи."
Защо при дефолтен ctor да се освободят и трите пойнтера - защо ще освободи паметта, сочена от copy.data, this->data и other.data ?
Примерно: int num = 123; int * ptr1 = # int * ptr2 = ptr1; delete ptr1; Нали остава един пойнтер, който дочи към данните (ptr2)? Защо данните да ги няма вече?
Поздрави!
Този пример не е много удачен, защото пойнтърите са към памет, заделена в стека и принадлежаща на локална променлива (num), която памет следва да бъде освободена едва след като num излезе от скоуп, но дори и така, програмата ще гръмне при опит за дереференциране на ptr2 след delete на ptr1.
Следният пример е по-удачен за илюстриране на проблема, който изглежда ти убягва в тази серия от въпроси:
Няма значение колко пойнтъра сочат към дадена памет - броят им не гарантира валидността на паметта.
За да освободим тази памет е достатъчно да извикаме delete през един от пойнтърите, което автоматично оставя другите пойнтъри да сочат към памет, която вече се използва от системата за други неща.
Представи си го така:
Имаме бомба (заделена памет), свързана с 5 независими детонатора (пойнтъри). Всеки детонатор може да взриви бомбата и това състояние ще е валидно до момента, в който някой от тях не бъде активиран (delete). От този момент нататък, бомбата (паметта) вече не съществува и останалите детонатори (пойнтъри) няма как да бъдат използвани за да я активират (достъпят).