This is a follow up to my previous question,
Initializing a class using malloc
Accepted answer on the question works and gives me new/delete on the avr-gcc, here is the problem but my overloaded new delete wracks havoc on regular gcc, what is the proper way to overload new delete all my classes derive from a common base class so ideally i would like to just override new delete for my object so it does not mess with stl stdlib etc.
'new' and 'delete' can overloaded inside the common Object base class. So, that will be applicable only to that hierarchy.
class Object {
public:
void* operator new (size_t size);
void operator delete (void *p);
};
class Derived : public Object {
// uses the above versions of new/delete
};
[Note: It's an added advantage for you as all your class are getting derived from a common Object class (as mentioned in your question and the link)]
Overload the new & delete inside your own class & not Globally.
For eg: If name of your common class is YourClass, You can overload them as follows:
void *YourClass::operator new(size_t size)
{
void *p;
cout << "In overloaded new.";
p = malloc(size);
if(!p)
{
throw std::bad_alloc; //Throw directly than with named temp variable
}
return p;
}
void YourClass::operator delete(void *p)
{
cout << "In overloaded delete.\n";
free(p);
}
void *YourClass::operator new[](size_t size)
{
void *p;
cout << "Using overload new[].\n";
p = malloc(size);
if(!p)
{
throw std::bad_alloc;
}
return p;
}
void YourClass::operator delete[](void *p)
{
cout << "Free array using overloaded delete[]\n";
free(p);
}
All classes derived from YourClass will be able to use these overloaded new and delete operators.
Related
I am trying to overload the new operator in a class but it does not work. When I try to overload it globally, it does work but not in a class.
I have these 2 in my class, but when new is called in a class for an int or something, it does not run. If I take it out of the class (global) it does work.
EDIT: It looks like the new overload is designed to run when an object of my class type is created with new. I want to instead make it run when anything new is made inside my class. How do I do this?
void* LeakCheck::operator new(size_t size)
{
cout << "Allocating memory..." << endl;
auto newObject = memoryManager.allocate(size); //calls malloc
return newObject;
}
void LeakCheck::operator delete(void* objectPtr) noexcept
{
cout << "Deallocating memory..." << endl;
void** ptr = reinterpret_cast<void**>(objectPtr);
memoryManager.deallocate(ptr, 0); //calls free
}
I am trying to understand overloading new operator. I wrote the code as below.
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;
class loc
{
int lo, la;
public:
loc()
{
}
loc(int x, int y)
{
cout << "In constructor\n";
lo = x;
la = y;
}
void show()
{
cout << lo << " ";
cout << la << endl;
}
void *operator new(size_t sz);
void operator delete(void *p);
};
void *loc::operator new(size_t sz)
{
cout << "in Overloaded new\n";
void *p = malloc(sz);
return p;
}
void loc::operator delete(void *p)
{
cout << "in Overloaded delete\n";
free(p);
}
int main()
{
loc *p1 = new loc(10, 20);
p1->show();
delete p1;
return 0;
}
I thought it won't call the constructor because I overloaded the new operator with malloc function call inside overloading function. But the output is as below.
in Overloaded new
In constructor
10 20
in Overloaded delete
That means constructor is getting called. How this is possible? Does this mean will malloc() call constructor?
A new expression results in two separate things happening: allocation of the memory needed by the object begin created, and initialization of the object.
The new operator, on the other hand, just handles the allocation part. When you overload the new operator with respect to a specific class, you are replacing the allocation of memory to the object.
This division of functions makes sense when you realize that not all objects are allocated on the heap. Consider the following case:
int main() {
string someString;
..
}
The local variable is not dynamically allocated; new is not used; however the object still needs to be initialized so the constructor is still called. Note that you did not need to explicitly call the constructor - it is implicit in the language that an appropriate constructor will always be called to initialize an object when it is created.
When you write a 'new expression', the compiler knows to emit instructions to invoke the new operator (to allocate memory as needed) and then to call the constructor (to initialize the object). This happens whether or not you overload the new operator.
I am using c++11 (g++ v4.7.2)
I've overloaded operator new and operator delete for "Base" class. Apparently they should not call constructor/destructor upon call of new/delete because I've not implemented ctor/dtor call in overloaded new/delete. But the output is contrary to that
//Output of below program
Base new opnd.cpp 87
Base ctor
10
Base dtor
Base delete
Why ctor/dtor are being called for overloaded operator new/delete?
#include <iostream>
using namespace std;
#define NEW new(__FILE__, __LINE__)
#define DELETE delete
class Base
{
public:
Base():m_i(10){ cout << "Base ctor" << endl; }
virtual ~Base(){ cout << "Base dtor" << endl; }
void* operator new(size_t size, const char* file, int line) throw(std::bad_alloc);
void operator delete(void *rawMem, size_t size);
int geti(){ return m_i; }
private:
int m_i;
};
void* Base::operator new(size_t size, const char* file, int line) throw(std::bad_alloc)
{
void *p;
cout << "Base new " << file << " " << line << endl;
//Handle 0 byte requests
if(size == 0)
size = 1;
if(size != sizeof(Base))
{
return ::operator new(size); // To handle new requests for derived classes
}
while(true)
{
p = malloc(size);
if(p)
return p;
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
if(globalHandler) (*globalHandler)();
else throw std::bad_alloc();
}
}
void Base::operator delete(void *rawMem, size_t size)
{
cout << "Base delete" << endl;
if(rawMem == 0)
return;
if(size != sizeof(Base))
{
::operator delete(rawMem); //To handle delete requests for derived classes
return;
}
free(rawMem);
}
int main()
{
Base *b = NEW Base;
cout << b->geti() << endl;
DELETE b;
return 0;
}
An operator new function (be it the global one or a class-specific one) is not the entire implementation of a new expression. It's only the allocation function. When you write new T in your code, the following happens:
An appropriate allocation function named operator new is chosen and called to obtain space for the object.
T's constructor is called on the space obtained from point 1.
This means there is no way to bypass constructor invocation by writing your own operator new - invoking the constructor is done by the language, not by the allocation function.
'Operator new' and 'new Operator' are two distinct things. When we use new to create some object like
MyClass* ca= new MyClass();
we are using the 'new Operator'. It does two things:
Calls 'Operator new' to allocate enough memory. It can be overloaded as you did.
Calls the constructor of the object to set initialization data.
These 2 steps will be executed no matter how the space is allocated. Hence after allocating memory using your overloaded 'Operator new', the constructor is called.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++'s “placement new”
I just learned about the placement new operator and tried creating my own memory manager.
Here is the code of my template base class for Memory
#ifndef _MEMORY_BASE_H_
#define _MEMORY_BASE_H_
//=========================================!
#include <new>
#include <exception>
#include <iostream>
//=========================================!
using namespace std;
//=========================================!
template <typename T>
class Memory_Base
{
public :
//standard new
void* operator new(size_t T);
// placement new
void* operator new(size_t T,void* pAddress);
//standard delete
void operator delete(void* pAny);
};
//=========================================!
// Implementation
//=========================================!
template <typename T>
void* Memory_Base<T>::operator new(size_t T)
{
cout << "Memory_Base<T>:: new called" << endl;
void* pTemp = malloc(sizeof(T));
if(!pTemp)
throw bad_alloc();
else
return pTemp;
}
//=========================================!
template <typename T>
void* Memory_Base<T>::operator new(size_t T,void* pAddress)
{
cout << "Memory_Base<T>:: placement new called" << endl;
return pAddress;
}
//=========================================!
template <typename T>
void Memory_Base<T>::operator delete(void* pAny)
{
cout << "Memory_Base<T>:: delete called" << endl;
free(pAny);
}
//=========================================!
#endif
Now, i inherited myclass from above class,in another header file , something like as below
#ifndef _MY_CLASS_H_
#define _MY_CLASS_H_
//=========================!
#include "Memory_Base.h"
//=========================!
class MyClass :public Memory_Base<MyClass>
{
private :
int ma;
public :
MyClass():ma(-1){}
~MyClass(){}
};
//============================!
#endif
Now, in my main, i am trying to create objects of myclass in the following manner
//============================!
#include "MyClass.h"
//============================!
int main()
{
// This is how new for MyClass is called
MyClass* pMyClass = new MyClass();
// This is how placement new for MyClass is called
MyClass obj[10];
MyClass* pMyClass1 = new(&obj)MyClass();
return 0;
}
//============================!
Questions ::
1. When i run main, the base address of obj and pMyClass1 were the same, as expected. However, i am just returning the pointer pAddress, then how the placement new works ?
my obj[10], is in stack, but, the destructor is not getting called.
Any ideas ?
Atul
P.S :: I have to implement the new[] and delete[] in Memory_Base.
MyClass obj[10];
Allocates and creates 10 objects of the type MyClass on the local storage.
Further,
MyClass* pMyClass1 = new(&obj)MyClass();
Just calls the constructor MyClass::MyClass(). The this pointer in the MyClass constructor will be equal to &obj. The returned pointer pMyClass1 will therefore be equal to &obj.
Also, In case of placement new it is your responsibility to destroy the placed object by explicitly calling the destructor, the placed objects destructor wont be called implcitly.
Since, the array of objects since placed on stack will be deallocated once the program returns in your case.
We want to work on low latency system, heap allocation is costlier in the application. but for some extent object creation on heap is allowed. Thats why we want indication whether object is created is on heap or not..?
Is the below methodology is the correct way to find out object created on heap memory..?
Will have generic class where new and delete operator is overloaded to maintain heap allocated pointers....
#include <iostream>
#include <set>
using namespace std;
class MemStat //base class
{
typedef set<MemStat*> POINTERS;
static POINTERS m_ptrlist;
public:
void* operator new (size_t size)
{
MemStat* ptr = ::new MemStat;
m_ptrlist.insert(ptr);
return ptr;
}
void operator delete(void* dptr)
{
MemStat* ptr = static_cast<MemStat*>(dptr);
m_ptrlist.erase(ptr);
::delete ptr;
}
// void* operator new[] (size_t sz);
// void operator delete[] (void*);
bool is_on_heap() { m_ptrlist.find(this) != m_ptrlist.end(); }
protected: // ctor & dtor are protected for restrictions
MemStat() { }
virtual ~MemStat() { }
MemStat(const MemStat&) { }
const MemStat& operator=(const MemStat& ) { return *this; }
};
MemStat::POINTERS MemStat::m_ptrlist;
for the end user classes which we need to check for the heap creation will be derived from MemStat class uses new & delete operator call while instantiating base class object.
class MyClass : public MemStat //end user class
{
};
int main()
{
MyClass* myptr = new MyClass;
MyClass obj;
cout << myptr->is_on_heap() << endl; //results into yes
cout << obj.is_on_heap() << endl; //reults into no
delete myptr;
}
Note that your scheme fails miserably as soon as a MyClass object is a sub-object (inherited or contained) of another object which might or might not by allocated dynamically. (And the tricks I know for preventing dynamic allocation fail on that one as well.)
So what you're doing just further slows down heap allocation without gaining much. Except for a few very rare circumstances, where an object is allocated is something your class' users decide.
If they think they need to dynamically allocate one, who are you to disagree?