Loading...
Jovanna avatar Jovanna 186 Точки

живот на променлива, създадена чрез динамично заделена памет

Здравейте,

Защо като се излезе от скоуба, да се изтрива 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];

}

Поздрави!

Тагове:
0
C++ Programming 08/11/2018 20:55:50
Jovanna avatar Jovanna 186 Точки

Пост2/Пример 1 : Какво означава: "... след излизане от скоуп nextArr просто ще изчезне, но без да се трие паметта, сочена от него" ?

и още две ситуации за изясняване :-)

Пост3/СИТ1/ Приемаме че имаме деструктор, разписан както трябва , но имаме дифолтен copy-assignment operator= и дифолтен copy-ctor. 

Правилна ли е следната логика?: other пристига по референция; на copy полето с data сочи към data на оригинала. Пренасочваме и this->data да сочи към data на оригинала. Скоупът се затваря и се делийтва с деструктора copy, т.е., един от пойнтерите сочещи към data на оригинала бива изтрит (copy.data),  но остават два пойнтера, които сочат към оригиналната data: на оригиналният обект other  и на *this:

class Array { int* data; int 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;

       }

Пост3/СИТ2/ Коректно ли е написан кода (имаме правилни TheBig3):

       Array<T>& operator=(Array<T> other) {  //Получаваме копие на other        

             delete[] this->data;

             this->data = other.data;  

             this->size = other.size;  

             other.data = nullptr;  //Тук предполагам, трябва да има това пренасочване към nullptr?

             return *this;

       }     

Поздрави!

0
11/11/2018 14:58:17
MartinBG avatar MartinBG 4803 Точки

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 оператор е коректен

2
11/11/2018 22:48:51
Jovanna avatar Jovanna 186 Точки

Пост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 = &num; int * ptr2 = ptr1; delete ptr1;  Нали остава един пойнтер, който дочи към данните (ptr2)? Защо  данните да ги няма вече?

Поздрави!  

0
11/11/2018 23:46:25
MartinBG avatar MartinBG 4803 Точки

Този пример не е много удачен, защото пойнтърите са към памет, заделена в стека и принадлежаща на локална променлива (num), която памет следва да бъде освободена едва след като num излезе от скоуп, но дори и така, програмата ще гръмне при опит за дереференциране на ptr2 след delete на ptr1.

 

Следният пример е по-удачен за илюстриране на проблема, който изглежда ти убягва в тази серия от въпроси:
 

int* ptr1 = new int(123); 
int * ptr2 = ptr1; 
std::cout << *ptr1 << std::endl; // 123
std::cout << *ptr2 << std::endl; // 123
delete ptr1;
std::cout << *ptr2 << std::endl; // random number

 

Няма значение колко пойнтъра сочат към дадена памет - броят им не гарантира валидността на паметта.

За да освободим тази памет е достатъчно да извикаме delete през един от пойнтърите, което автоматично оставя другите пойнтъри да сочат към памет, която вече се използва от системата за други неща.

 

Представи си го така:

Имаме бомба (заделена памет), свързана с 5 независими детонатора (пойнтъри). Всеки детонатор може да взриви бомбата и това състояние ще е валидно до момента, в който някой от тях не бъде активиран (delete). От този момент нататък, бомбата (паметта) вече не съществува и останалите детонатори (пойнтъри) няма как да бъдат използвани за да я активират (достъпят).

2
12/11/2018 03:36:28
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.