views:

86

answers:

6

I have the following code

#include <iostream>
#include <cstddef>
#include <string>
#include <memory>


class Object
{
public:
       Object()
       {
               std::cout << __PRETTY_FUNCTION__ << std::endl;
       }
       std::string x;

       void *operator new( size_t bytes )
       {
               std::cout << __PRETTY_FUNCTION__ << " : bytes = " << bytes << std::endl;
       }

       void operator delete( void * arg )
       {
               std::cout << __PRETTY_FUNCTION__ << std::endl;
       }
};



int main( int c, char *v[] )
{
       // std::auto_ptr< Object > pObject( new Object() );
       Object *o = new Object();
       delete o;
}

and it produces this output...

static void* Object::operator new(size_t) : bytes = 8

and then core dumps.

Given that I don't get the output from the operator delete() method and that it core dumps. I'm assuming that my operator delete() method isn't being invoked.

Can anyone shed any light as to why it isn't being invoked?

Thank you for focusing on the core dump against my ALL CAPS RANTS because it actually turned out to be the problem.

EDIT-- Ok, Where do I start.... I'm incredibly sorry for ranting. We've all been there, under pressure to meet a deadline and something innocuous appears to be causing an issue and we're convinced it's one thing when in fact it's another. This has taught me a valuable lession... I need to start listening.... I fully appreciate all of help and advice given here.

Thx Mark.

+1  A: 

Why doesn't your operator new return a value? It is declared to return void * but dosn't return anything. This means your compiler should have given a compile error, apparently it didn't, and well the crash may be becaue of that.

On the other hand, if this, as you say, is an example, then maybe you returned 0 from new, in which case operator delete is not being invoked because calling delete on a 0 pointer is equivaent to an empty statement.

malloc something in new and return it, and operator delete will be invoked

Let's be more specific here:

  1. Your core dump is obviously because you don't return a value.

  2. delete o is a delete expression which will only eventually call your operator delete, and it will do so ONLY if the pointer is not NULL. As said, it must be a valid pointer

Armen Tsirunyan
it's just an example. I don't care what hte return value is because I don't use it in operator delete().
ScaryAardvark
@ScaryAardvark: Can you give a complete compilable crashig example? 'Cause yours is NOT compilable
Armen Tsirunyan
Not returning a value means your stack gets corrupted - this is why you crash.
Michael Anderson
Please don't focus on the core dump.. Focus on why operator delete() isn't being called as that was my original question.....
ScaryAardvark
@scaryaardvark: see my edit
Armen Tsirunyan
Please look at the problem.. It has NOTHING to do with wether memory was allocated or the return value is (RANDOM). THE PROBLEM IS THAT MY OPERATOR DELETE() ISN'T BEING INVOKED...
ScaryAardvark
@Armen, this is compilable on gcc4.1.2
ScaryAardvark
@ScaryAardvark: That's the reason for the core dump. You MUST return a value of type void* from ANY functino that is declared to return void*, otherwise it is undefined behavior, including core dump. It DOES matter whether memory is allocated. If you return 0, delete will NOT be invoked. Try it :)
Armen Tsirunyan
ScaryAardvark: If you're so damned sure of what the problem is why are you bothering to ask questions on StackOverflow? It does indeed have EVERYTHING to do with whether memory was allocated or not and whether the return value is random or not. (C.f. my answer and a few others for details.) Humility is one of the most powerful weapons in the arsenal of a developer.
JUST MY correct OPINION
Sorry couldn't resist the urge to reply this, but "Humility is one of the most powerful weapons in the arsenal of a developer. – JUST MY correct OPINION" reads like a great oxymoron :) +1 for the comment from me!
usta
@usta: Irony, too, is a very powerful weapon in the arsenal of the developer. ;)
JUST MY correct OPINION
@JUST MY correct OPINION: LOL! Thumbs up ;)
usta
@usta, @JUST: Guys, you'd be better off opening a new thread for that: "What could count as a very powerful weapon in the arsenal of the developer?" I'd vote it up :)
Armen Tsirunyan
+5  A: 

operator new must return a pointer to sufficient memory (or throw an exception), because the new-expression will also be trying to invoke the constructor of Object for the allocated memory. The problem is not with delete, it's new Object that cannot complete normally.

visitor
+9  A: 

Your new expression does two things. It invokes the appropriate operator new function to allocate some memory and then constructs a new Object in the memory pointed to by the return value of operator new.

As you don't have a return statement in your operator new you get undefined behaviour. If we explore what is likely to happen, it is likely that the function returns a random value for the return value and the compiler attempts to construct the Object (including its owned std::string) at an invalid address.

This will cause a crash before your code ever reaches the delete statement.

Charles Bailey
+2  A: 

You're crashing well before delete() is called, because you haven't allocated any storage for std::string x; - if you comment out this instance variable then the code should compile (with warnings) and run OK.

Paul R
Thank you......
ScaryAardvark
@Paul R: if undefined behavior is "run OK"... :(((
Armen Tsirunyan
@Armen: yes, strictly speaking it's UB, but in practice it will probably "run OK" in most environments. I'm not advocating for this kind of code though !
Paul R
+3  A: 

If I change main to be

int main( int c, char *v[] )
{
       // std::auto_ptr< Object > pObject( new Object() );
       Object *o = new Object();
       std::cout<<"I'm ok here"<<std::endl;
       delete o;
}

then I get

static void* Object::operator new(size_t) : bytes = 4
Bus error

and cout is never called.. This is because you are running into undefined behaviour. (In particular it looks like on many compilers the constructor is being called in the location that is undefined)

If I change new to be

   void *operator new( size_t bytes )
   {
           std::cout << __PRETTY_FUNCTION__ << " : bytes = " << bytes << std::endl;
          return new char[bytes];
   }

I get

static void* Object::operator new(size_t) : bytes = 4
Object::Object()
I'm ok here
static void Object::operator delete(void*)

so delete will be called if you do the right thing.

Michael Anderson
There's nothing being corrupted on the call stack. He's just returning whatever random garbage was in the EAX register (for Intel machines) as a pointer to a block of memory. This bogus pointer is then dereferenced for the call to the constructor.
JUST MY correct OPINION
@JUST MY correct OPINION: What if the function call was implemented so that the callee pushes the return value onto stack, and the caller pops that? In that case, as there would happen a pop without matching push been done earlier, the stack *would* get corrupted.
usta
If it was so implemented, then yes, indeed, it would corrupt the stack. Now all you have to do to have a point here is point to a C++ compiler anywhere that implements returns this way. (Hint: this is a very difficult task.)
JUST MY correct OPINION
@JUST MY correct OPINION: Indeed, very difficult to find such an implementation which would store a return value onto stack instead of a register, when the return value is something as small as a pointer. Just a theoretical note from me, which doesn't make any practical difference in this case :)
usta
Yeah I guess i this case it may not corrupt the stack (though I've seen that happen a lot from statements with no return in other code .. I hate tracking those particular bugs down). But it certainly runs into undefined behaviour, so corrupting your stack is among the nicer things that it is allowed to do. .. updated my post to reflect that fact.
Michael Anderson
+1  A: 

I would have thought that the fact your constructor wasn't being called either was a bit of a clue. As is the fact that you've got a segmentation fault going on when you run it. What happens with new Object()? Your memory is allocated (this is your operator new) and then your constructor is called. How is your constructor called? By dereferencing the pointer to your allocated memory....

If you stub out your operator new, everything works fine: you get the memory from the runtime, the constructor is called, the operator delete is called. If you make an operator new that actually does things, you'll see operator delete (and your constructor) getting called too.

JUST MY correct OPINION