class implementation of operator delete() not being invoked - c++

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.

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.

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.

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.

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.

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:
Your core dump is obviously because you don't return a value.
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

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.

Related

Im Facing a Problem With Destructor Called Twice in C++

EDIT: I had to use unique_ptr or follow the rule-of-five I'm still learning about it so I used unique_ptr and it worked. But I have a question, the destructor now is being called twice and I think that is no problem as long as the block of memory that the pointer is pointing to is not being freed twice, Right??
I made a simple "String" class in c++ (Know it from The Cherno). So I made it and it seems to work well until I decided to add an empty constructor to be able to initialize it with no parameter but when I did that the destructor is being called twice.
// here is the header file
#pragma once
#include <iostream>
using namespace std;
class String
{
private:
//Hold the raw of chars in the heap memory
char* m_Buffer;
//The size of the buffer in heap
unsigned int m_Size;
public:
//An empty Constructor
String()
: m_Buffer(nullptr), m_Size(0)
{
cout << "created Empty." << endl;
}
// A Constructor
String(const char* string)
{
m_Size = strlen(string);
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, string, m_Size + 1);
m_Buffer[m_Size] = 0;
}
// A destructor
~String()
{
cout << "Destroy!!" << endl;
delete[] m_Buffer;
}
// Function resposable for coping
String(const String& other)
: m_Size(other.m_Size)
{
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
}
char& operator[](unsigned int& index)
{
return m_Buffer[index];
}
friend std::ostream& operator<<(std::ostream& stream, const String& other);
};
std::ostream& operator<<(std::ostream& stream, const String& other)
{
stream << other.m_Buffer << endl;
return stream;
}
//here is the main file
#include "LclString.h"
int main()
{
String a = "asdc";
a = "ads"; // The Destructor is being called here the first time
cin.get();
} // and here is the second time
A piece of advice will be appreciated
......................................
Your destructor calls delete[] m_Buffer. A pointer may never be deleted twice. If you do delete a pointer twice, then the behaviour of the program will be undefined. You must avoid ever doing that. To achieve avoiding that, you must make sure that no two instances of the class have the same pointer value in the member.
Consider what the implicitly generated assignment operator of your class does. It copies all members from the right hand operand to the left hand operand. Can you see why that is a problem? All members include the m_Buffer pointer. The assignment operator will cause two instances of the class to have the same pointer. And when the second instance is destroyed, it deletes that same pointer again. And the behaviour of the program is undefined.
There is another related problem, the implicit assignment operator overwrites the old m_Buffer. Who's going to delete the pointer that was overwritten? No-one is going to delete it because the value was lost by the assignment. That's a memory leak.
Conclusion:
Avoid using owning bare pointers.
Avoid using new and delete directly.
If you have a user defined destructor, then you probalby also need user defined copy/move constructor and assignment operator. This is known as rule of 5 (previously rule of 3). If you use smart pointers instead of owning bare pointers, then you usually don't need a user defined destructor.

Getting issue with placement new and delete operator

I have written the following code for placement new and delete operator functions. Can you please tell the issue with the code below.
// new_operator.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
using namespace std;
class Mem
{
public:
void* alloc(size_t sz) { return malloc(sz); }
void dealloc(void* ptr) { free(ptr); }
};
class Object
{
public:
Object() { cout << "In Constructor Object()" << this << endl; }
~Object() { cout << "In Destuctor ~Object()" << endl; }
void* operator new(size_t sz, Mem* handle)
{
Object* x1 = (Object*)handle->alloc(sz);
return x1;
}
void operator delete(void* ptr, Mem* handle)
{
cout << "Here\n";
((Object*)(ptr))->~Object();
handle->dealloc(ptr);
}
};
int main()
{
Mem* memory = new Mem;
Object* obj = new (memory) Object;
cout << "Obj is " << obj << endl;
delete (obj, memory);
delete memory;
return 0;
}
I'm getting runtime crashes at the time when delete operator function starts executing. Can anyone please tell what I'm doing wrong.
Placement delete is called to free memory when a constructor called from placement new fails. You are not supposed to call any destructors from any version of operator delete, because operator delete frees memory that is left after an object that used to reside there is destroyed (or was never constructed to begin with).
The only way to explicitly call a placement operator delete is to spell out two words operator delete, thus making a function-call-expression. You cannot invoke it from a delete-expression (there is no placement-delete-expression syntax). In your case, you would need to use a qualified name: Object::operator delete. Note that if you remove the explicit destructor call from Object::operator delete, as you should because of the above, the destructor will not be called. There is no way to both invoke the destructor and free the memory in a single call to a placement delete. The easiest way to handle this is to create and use a non-static member function, say void Object::destroy(Mem*).
delete (obj, memory);
On this line, you delete only memory, not obj. The left hand operand of comma operator is discarded. Since the expression obj has no side-effects, this is probably a mistake.
delete memory;
On this line, you delete memory again. This results in undefined behaviour.
Note that you never destroy the dynamic Object that you created. The custom placement delete overload will only be called in case the placement new throws an exception. In other cases, your malloc will leak.

Extra construction when using placement new with a storage class

In a situation where I want to avoid dynamic memory allocations, I'm replacing the new operator with a process that essentially uses the memory of some statically allocated object (the Storage class below). You can see a minimum working example below:
#include <cassert>
#include <iostream>
struct Object {
Object() { std::cout << "Creating a new object\n"; }
static void *operator new(size_t);
static void operator delete(void *p);
};
static struct {
Object where;
bool allocated = false;
} Storage; // 1
void *Object::operator new(size_t) {
assert(!Storage.allocated);
auto p = ::new (&Storage.where) Object; // 2
Storage.allocated = true;
return p;
}
void Object::operator delete(void *p) {
assert(Storage.allocated);
static_cast<Object *>(p)->~Object();
Storage.allocated = false;
}
int main() { Object *obj = new Object; } // 3
My question has to do with the number of calls to the constructor. When I run the above program, I expect to call the constructor twice (marked as 1 and 2 in the comments above) but the output I get is:
Creating a new object
Creating a new object
Creating a new object
Why is the constructor called thrice? I'd only expect constructor calls, by the static object and the call to placement new. I tried tracing the code with gdb, but it makes no sense to me, since position //3 is where the third call to the constructor originates.
The reason I want to know is because a case has emerged, where this extra constructor call causes unwanted side-effects; up until now, this extra call was unnoticed.
For some odd reason, your operator new calls the constructor when it should just allocate memory. This means that the call to new winds up calling the constructor of Object twice. There is one call in operator new and another call in main.
You probably want this:
void *Object::operator new(size_t) {
assert(!Storage.allocated);
Storage.allocated = true;
return reinterpret_cast<void *> (&Storage.where);
}
Imagine if the constructor took an integer parameter and the line in main looked like this:
Object *obj = new Object(7);
How would operator new know how to properly construct the object? That's not where you're supposed to do that!
Object *obj = new Object; does two things:
Allocates memory by calling operator new
Calls the constructor.
Your operator new calls the constructor as well, so the constructor is called twice by this statement (and once for the global variable initialization).
Note that delete is the same. delete obj; does two things:
Calls the destructor.
Deallocates memory by calling operator delete
Your operator delete shouldn't call the destructor either, because then the destructor is called twice.

Is it possible to perform callbacks to the global operators `new` and `delete`?

Here's what I'm doing:
#include <iostream>
using namespace std;
class Test
{
public:
int i;
Test();
Test(int x);
~Test();
static void operator delete(void * t);
};
Test::Test() : i(1) { cout << "constructing" << endl; }
Test::Test(int x) : i(x) { cout << "constructing w/ arg" << endl; }
Test::~Test() { cout << "destructing" << endl; }
Test::operator delete(void *self)
{
cout << "deleting" << endl;
((Test *) t)->~Test(); // call destructor since it isnt called otherwise
::delete(t); // actually delete memory
}
template <typename T> // too lazy to figure out correct type
void callback(Test *t, T fn)
{
(fn)(t); // delete operator is implicitly static so this syntax is correct
}
int main()
{
Test *t = new Test();
callback(t, &Test::operator delete); // deletes t
}
I've noticed that unless operator delete is overloaded for my class, the previous snippet will fail to compile. If it's included, it will compile and work as expected (first the constructor is called, then overloaded delete, then the destructor, each exactly once).
I thought of passing the global delete operator ::operator delete, but that doesn't work either (I get an unresolved overloaded function call). I can call it without trying to get its address just fine.
Is what I'm doing even possible without defining my own overload of ::operator delete?
I know that there is basically no use case where I'd ever need to use something like this. I know that ::operator delete is not a general use thing, and that it doesn't call destructors....
Global operator new/delete are overloaded functions - you'll need to cast to the correct function pointer type:
callback(t, static_cast<void(*)(void*)>(::operator delete));
Edit: I'm expanding my answer to clarifiy some things.
It is true that the destructors are not called by the global operator delete. It's just deallocation function responsible to return the memory back to runtime. Calling destructors is the job of delete expression:
Delete expression first calls the destructors of the object (or objects, if we use array form) its pointer argument points to and then calls the deallocation function (if the pointer being deleted is of class type, it looks for it in the scope of that class first and calls the global one if it doesn't find it).
Another important thing to note is that using a void* pointer in delete expression is undefined behaviour, which is what you do in your overload:
cout << "deleting" << endl;
((Test *) self)->~Test();
::delete(self); // this is delete expression using void*, UB
You're not calling global operator delete, for that you'd need to say ::operator delete(t);. You have a delete expression and the scope resolution operator just tells it to not look inside class scope for deallocation function.
If you change it to this ::delete( (Test*) self); you'll see destructing being printed twice, again UB.
All in all, don't call the destructor inside operator delete, it's not its job.

Can calls to memory allocation and constructor be interleaved with other operations required to perform a "new" expression?

Suppose I have a following class:
class Sample {
public:
Sample( int ) {}
};
some function returning an int
int SomeFunction()
{
return 0;
}
and this code:
Sample* sample = new Sample( SomeFunction() );
Now I expect the following sequence:
SomeFunction() is run, then
::operator new() is run to allocate memory for the object, then
class Sample constructor is run over allocated memory
Is this order fixed or can it be changed by an implementation such that say first memory is allocated, then SomeFunction() is called, then constructor is run? In other words, can call to operator new() function and call to class constructor be interleaved with anything?
The order is unspecified. [5.3.4]/21 reads:
Whether [operator new] is called
before evaluating the constructor
arguments or after evaluating the
constructor arguments but before
entering the constructor is
unspecified. It is also unspecified
whether the arguments to a constructor
are evaluated if [operator new]
returns the null pointer or exits
using an exception.
The order of the calls to operator new and SomeFunction is unspecified - so it may change based on optimisation settings, compiler version, etc.
The constructor call I think has to come last.
Yes, it could be interleaved.
class A
{
public:
A(int i)
{
cout << "constructor" << endl;
}
void* operator new(size_t size)
{
cout << "new" << endl;
return malloc(size);
}
void operator delete(void*, size_t)
{
cout << "delete" << endl;
}
};
int f()
{
cout << "f()" << endl;
return 1;
}
int main()
{
A* a = new A(f());
}
Output:
new
f()
constructor
Though not guaranteed by the standard, compilers do have a reason to allocate memory first. If memory allocation fails, the constructor won't be called at all. So evaluating constructor arguments too early is probably not a good idea.
Actually, what I think happens is:
new is used to allocate raw memory
SomeFunction() is called returning a value X
the constructor is called, with X as a a parameter
but I could be wrong. I would say that this shows that you shouldn't be worrying about the order.
You can't change what happens when you run that line of code. You can run some different lines of code.
void * p = ::operator new (sizeof (SomeFunction));
SomeFunction temp;
SomeFunction* sample = new (p) SomeFunction(temp);