1

Allocated some memory-

buf = new char[sizeof(student_rec)*5];//student_rec is class

Then create an array of class 'student_rec' using placement new.

student_rec *sr1;
sr1 = new(buf)student_rec[5];

Call the method fun() for each class.

for(i=0; i<5; i++)
{
    sr1[i].fun();
}

And after that call the destructor for each class.

i = 5;
while(i)
    sr1[--i].~student_rec();

And delete the allocated memory chunk using delete.

delete [] buf;

Then why after that using sr1[2].fun() it prints 'hello' ? When i delete the memory using delete [] buf then there is no memory present for object. Then why sr1[2] works fine ?

Here is my code-

class student_rec
{
    private:

       string name;
       int roll_no;
       float percentage;

    public:

       student_rec()
       {
           cout<<"zero argument constructure\n";
       }

       ~student_rec()
       {
           cout<<"destructure\n";
       }

       student_rec(char *n, int r, float per)
       {
           cout<<"three argument constructure\n";
           name  = n;
           roll_no = r;
           percentage = per;
       }

       void show()
       {
           cout<<"Name= "<<name<<endl;
           cout<<"Roll No.= "<<roll_no<<endl;
           cout<<"Percentage= "<<percentage<<endl;
       }

       void fun()
       {
           cout<<"hello\n";
       }

};

int main()
{
   char *buf;
   buf = new char[sizeof(student_rec)*5];
   student_rec *sr1;
   sr1 = new(buf)student_rec[5];
   int i;
   for(i=0; i<5; i++)
   {
       sr1[i].fun();
   }
   i = 5;
   while(i)
       sr1[--i].~student_rec();
   delete [] buf;
   sr1[2].fun();
   return 0;
}
  • 5
    Accessing deleted memory is [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior). That is, anything can happen: you may get zeros, previous result, pink elephants or your girlfriend's panties. Asking why you see what you see is forbidden by C++ standard ;) – Ivan Aksamentov - Drop Sep 17 '17 at 06:09
  • 1
    Read about [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior). Deleting an object don't clear it. – Basile Starynkevitch Sep 17 '17 at 06:09
  • To precise, "not clearing an object" is also an option for the result of the undefined behavior, as, basically, is any other possible event in the universe. Additionally, you may get different results in debug/release mode or on different OS or compiler or standard library or in another time of the day, or if it is raining. Okay I think i made myself clear ;) – Ivan Aksamentov - Drop Sep 17 '17 at 06:12
  • Because it hasn't been garbage collected yet? Because of the phase of the moon? The air temperature? Who knows? Bottom line is accessing deleted memory may lead to opening the gates to the secret kingdom of Narnia, or to the 7th circle of hell - thus highly discouraged as its undefined behavior. – Burhan Khalid Sep 17 '17 at 06:14
  • If you're going to use placement new read this: https://stackoverflow.com/questions/1022320/why-destructor-is-not-called-implicitly-in-placement-new – Retired Ninja Sep 17 '17 at 06:15
  • @BurhanKhalid garbage collected? –  Sep 17 '17 at 09:22
  • Why do you think you should call the destructor yourself? –  Sep 17 '17 at 09:23
  • This answer might help (it is for local variables, but is applicable here too): https://stackoverflow.com/a/6445794/3410396 – Revolver_Ocelot Sep 17 '17 at 09:57
  • @manni66 Because that's what using placement new requires. – Retired Ninja Sep 17 '17 at 17:21

1 Answers1

1

As the comments already mentioned: What you do is "Undefined Behaviour".

But for your special case, your function fun() did not access any data member of your class and is also not a virtual method, so nothing from your object will be used and so it works quite perfect, also if you will clear your memory, because there is really nothing in the objects memory, what is needed to call this function. As this, you can make this method a static one which then can be accessed without a object of that class.

The compiler knows the type of your pointer student_rec and it also knows that there is no access to any object so it will call simply the method without any data access in your allocated and freed memory.

The following code will also work but is also undefined behaviour:

class Bla
{
    public:
        void fun() { std::cout << "Hallo" << std::endl; }
};

int main()
{
    Bla* ptr=0;

    ptr->fun(); // access of 0 pointer? No-> no data access, simply function call! But never do that in real code ;)
}

The method is from the logic point of view part of the class and not of the objects. As you can see, we never create an instance of the class but the code will also work in most cases.

On gcc 6.1 it compiles and works also with -O0, so it is not dependent on optimization at all. No object data access, so it works without object. But remember: This is perfect invalid code! :-)

Edit: From the comments: Why valgrind did not catch such errors?

Quite simple: If we look into the details of what a compiler makes from a method, we get something like that: ( pseudo code! )

class Bla { void fun() { ... } };

is translated internally to:

Bla::fun( Bla* this ) { ... }

Dependent on the implementation of the compiler, typically the first function parameter is the pointer to the object itself. So the call of fun() results in calling Bla::fun( this ); At this point, it is fully independent of the value of this! So if, as given in my above code example, this is 0! And inside Bla::fun() nothing access the this pointer. So the code seems to be valid!

Valgrind itself checks only on the executable itself, so valgrind will not find an invalid access of data members because it simply find no access which is valid at all :-)

"if this works, what is the difference with static functions?"

If the method is defined as static, the compiler generates a function without the this pointer. So it is different.

"And how are we ever going to trace such errors?"

If your method is not static but did not access any data member, it is a design flaw. I can't see a reason why we should have a method without access to the objects data at all which is not declared static.

My advice here is, to check if you have such non static methods? But yes, I did not know if any compiler can generate a warning on such methods.

Klaus
  • 24,205
  • 7
  • 58
  • 113
  • This is freaky. Even `valgrind` does not complain about this. If this works, what is the difference with `static` functions? And how are we ever going to trace such errors? – Chiel Sep 17 '17 at 08:26
  • @Chiel: It's kind of like the difference between a `const` member function and a non-`const` one which doesn't change any fields. – einpoklum Sep 17 '17 at 09:23
  • @einpoklum: That you do not change data members did not mean that you do not access data members. So the above code will crash also with const access if the this pointer is invalid ( 0 in my example! ). I can't catch the point, where your comparison between static and const helps on this topic. – Klaus Sep 17 '17 at 09:28
  • I'm saying that a non-static method that doesn't use any instance data is implicitly static, just like a non-const method which doesn't change anything - and the compiler can notice these facts and use them for optimization. – einpoklum Sep 17 '17 at 09:58
  • @einpoklum. It is different, as `const` and non-`const` members functions that don't change fields are still valid. I find it very scary that in this example, neither the compiler, nor valgrind exposes an error, or triggers a warning. – Chiel Sep 17 '17 at 10:05