Розуміння оператора видалення на C ++

Розглянемо нижче код:

#include 
#include 
 using namespace std;

class A{ 
 public: 
     int x; 
 public: 
     A(){x=0;} 
     void fun1(){ 
         cout << "fun1 is called \n"; 
         cout << "Address of this is " << this <<< "fun2 called \n"; 
     } 
     ~A() 
     { 
             cout << "Object Destroyed" << endl; 
     } 
 }; 

 int main() 
 { 
     A* ptr=new A; 
     cout << "Address of ptr is " << ptr <fun1(); 
     ptr->fun2(); 
     return(0); 
 }

Вихід є:

$ ./TestCPP
Address of ptr is 0x20010318
fun1 is called
Address of this is 0x20010318
Object Destroyed
fun2 called

My question is that when we call delete in fun1() it destroys the object pointed by this pointer i.e at address 0x20010318. It calls the destructor as shown by output. Hence after calling fun1() the object at address 0x20010318 is destroyed and that memory is freed. Then why in the output we can see fun2() ? Is it just the garbage value ? I mean the object does not exist but at location pointed by ptr -> fun2() the definition of fun2() still exists?

Також може хтось, будь ласка, поясніть, як працює delete . Наприклад, якщо викликати new викликів operator new та constructor , то операція delete подібна?

Дякую

0
Ще більше задоволення: int main() {{A tmp; } щось ще(); } - припускаючи, що внутрішній блок не оптимізується через відсутність побічних ефектів, у всякому разі ....
додано Автор twalberg, джерело
додано Автор Tadeusz Kopec, джерело

7 Відповіді

Те, що ви робите, це технічно невизначена поведінка, так що, дійсно, щось може статися, наскільки це стосується стандарту.

That aside, the actual behavior you are seeing can be easily reasoned about. fun2 is a non-virtual function. The compiler will resolve the call to it at compile time. When the object is destroyed, the function is not destroyed. And when you call ptr->fun2(), your compiler just calls the function. Since the function doesn't rely on any member data, the output is quite predictable (even though, as far as the standard is concerned, it's not).

Here's a demonstration of me calling a non-virtual member function on a null pointer. Clearly this is wrong, and yet it prints statement exactly as expected: http://ideone.com/pddnGt

Це не означає, що код не поганий. Ви ніколи не повинні мати невизначену поведінку в коді. На нижчих рівнях оптимізації, для налагодження, компілятор може дуже добре викинути перевірки на подібні речі і зупинити програму з повідомленням про помилку або виключити виняток.

4
додано

Is it just the garbage value ? I mean the object does not exist but at location pointed by ptr -> fun2() the definition of fun2() still exists?

Так, це невизначена поведінка, але оскільки ніщо насправді не використовує пам'ять, вона здається , щоб "працювати" в порядку. Насправді це серйозна помилка. (NB При цьому визначення A :: fun2() ніколи не йде ніде, тобто коду, а не даних, тому існує протягом усього терміну дії програми, об'єкт у пам'яті ptr припиняє існувати, але визначення його функцій-членів не відбувається.)

Наприклад, якщо викликати new виклики operator new та конструктора, чи є подібна операція delete ?

Так, він закликає деструктор знищити об'єкт у цьому місці, після чого закликає оператора видалити , щоб звільнити пам'ять.

2
додано

Якщо ваш метод не є віртуальним і не містить посилання на член, він може працювати з деякими компіляторами, оскільки метод у збірці не потребує дійсного цього покажчика. У будь-якому разі, ви повинні бути вчинені з невизначеною поведінкою.

1
додано

Коли ви телефонуєте delete , операційна система повідомляється, що ця пам'ять вже не потрібна, і тому вона доступна для подальшого розподілу. Однак воно не буде автоматично витиратись.

У вашому випадку ця пам'ять не використовується жодним іншим користувачем перед вашим викликом до fun2 . Ніхто не намагався виділити жодну пам'ять в купі між двома викликами функції. Тому об'єкт все ще існує і ніколи не руйнується. Проте це не означає, що розподіл пам'яті неможливий між двома дзвінками (наприклад, переривання може спрацьовувати і пам'ять може бути виділена під час обробки переривання). Тому ніколи це не слід робити. :)

0
додано

Після того як delete викликається в fun1 , ваш виклик до fun2 є незаконним. C ++ не тримає вашу руку, тому що для цієї "невизначеної поведінки" все може відбуватися, включаючи належним чином називається fun2 .

По суті, delete викликає деструктор об'єкта, а потім звільняє пам'ять, просто протилежність new .

0
додано

Коли ви викликаєте невіртуальну функцію з класу, функція

class A { public: void function(int k) { ... } };

буде написано як щось подібне

void __A_function(A* this, int k);

Якщо ваша функція не пов'язана з покажчиком this , вона буде викликана як стандартна функція, при цьому параметр this знехтується.

Інша річ, яку я можу спрогнозувати, це навіть те, що вам це подобається

class A
{
private:
  int k;
public:
  A() : k(10) {}
  void function() { printf("%d\n",k); }
};

A* ptr=new A;
delete ptr;
ptr->function();

в більшості випадків він буде роздруковувати 10. оскільки пам'ять від new ще не очищена.

Я буду рекомендувати Inside C ++ Object Model для детального розуміння цього.

0
додано

Функція-член вирішується під час компіляції.

Ви можете зробити щось подібне:

A* ptr = NULL;
ptr->yourFunc();

Це буде працювати, поки ви не маєте доступу до сховища даних у об'єкті (та його VTable, тому ви не хочете, щоб виклик методу).

"Це" матиме значення null, і це буде добре. Але зняття будь-яких результатів призведе до сегментації.

0
додано
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147