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.
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.
Consider the following code which contains a class with overloads for new and new[]:
#include <iostream>
class my_class {
public:
my_class() {};
my_class(const my_class& rhs) {};
~my_class() {};
//the constructor also as applicable.
void * operator new(size_t sz);
void * operator new[](size_t sz);
void operator delete(void * ptr);
void operator delete[](void * ptr);
private:
};
void * my_class::operator new(size_t sz)
{
std::cout << "at operator new, sz is: " << sz << std::endl;
}
void * my_class::operator new[](size_t sz)
{
std::cout << "at operator new[], sz is: " << sz << std::endl;
}
void my_class::operator delete(void * ptr)
{
std::cout << "at operator delete, ptr is: " << ptr << std::endl;
}
void my_class::operator delete[](void * ptr)
{
std::cout << "at operator delete[], ptr is: " << ptr << std::endl;
}
int main(int argc, char ** argv)
{
my_class * ptr = new my_class;
my_class * arr_ptr = new my_class[1];
return 0;
}
Running this in the terminal (Cygwin) I see:
at operator new, sz is: 1
at operator new[], sz is: 9
Why is sz == 9 when operator new[] is called ? Who sets it? What does it depend on (eg. page size?)?
A new-expression, like new my_class does more than call operator new; operator new only allocates memory, and its parameter is the size of the memory it is supposed to allocate.
The parameter sz of operator new is 1 because that's the smallest possible instance; sizeof(my_class) is 1.
The parameter sz of operator new[] is 9 because that is how much memory the new[]-expression (new my_class[1]) requires for allocating an array of 1 instance of size 1.
The "extra" 8 is for keeping track of things like how many elements there are.
The size of the "extra" memory is implementation-dependent.
The runtime "sets" the value when you invoke the operator new. There is an implicit sizeof passed around. It is the same situation as with invoking member functions without implicitly passing around the pointer to the current instance this.
In your case you have a class with no members, so theoretically its size should be zero, however C++ allocates one byte (due to the fact that the objects must at least be addressable). That's why the result of the first allocation is 1 (assuming you fix your operators new/new[] to return something, until then you have UB). The second allocation returns 9 due to how C++ represents dynamic arrays, it puts some header somewhere (implementation defined) so it recognizes it is an array (so when invoking operator delete[], the latter behaves properly) and perhaps due to padding.
I am reading the source code of SGI standard template library. I find that the operator new function always has a double-colon in front of it. Like this:
T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
operator new can be directly called without adding the :: field, then why do the stl coders write it in this way? What trap or situation may it come to if we don't use the :: in front of them.
You can overload operator new for a class and prefixing it with "::" will call the global "default" operator new instead of a possible overload. For example:
#include <iostream>
class Foo
{
public:
Foo() { std::cout << "Foo::Foo()" << std::endl; }
void * operator new(size_t )
{
std::cout << "Foo::operator new()" << std::endl;
return static_cast<Foo *>(malloc(sizeof(Foo)));
}
};
int main()
{
Foo foo;
std::cout << "----------------------" << std::endl;
Foo * p = new Foo;
std::cout << "----------------------" << std::endl;
Foo * q = ::new Foo;
}
will print
Foo::Foo()
----------------------
Foo::operator new()
Foo::Foo()
----------------------
Foo::Foo()
Edit: The code snipped is indeed not about operator new that is defined in a class scope. A better example would be this:
#include <iostream>
namespace quux {
void * operator new(size_t s)
{
std::cout << "quux::operator new" << std::endl;
return malloc(s);
}
void foo()
{
std::cout << "quux::foo()" << std::endl;
int * p = static_cast<int*>(operator new(sizeof(int)));
}
void bar()
{
std::cout << "quux::bar()" << std::endl;
int * p = static_cast<int*>(::operator new(sizeof(int)));
}
} // namespace quux
int main()
{
quux::foo();
quux::bar();
}
which prints
quux::foo()
quux::operator new
quux::bar()
::operator new in C++ is the global memory allocator that is called every time a certain amount of bytes is needed for a single object. Note that the return value is a void * and that ::operator new(size_t) deals with raw bytes, not objects.
It is basically the C++ counterpart of malloc with simply a funny name.
A separate global allocator ::operator new[](size_t sz) is instead used to allocate memory for arrays of objects.
These two operators, their counterparts ::operator delete and ::operator delete[] and also the nothrow version of the allocators are used for all memory needs of the C++ runtime.
They may be implemented in terms of calls to malloc/free or not. What is guaranteed is that malloc and free dont use them (thus you can call malloc and free if you want to reimplement these functions without the risk of infinite recursion).
To call the operator new from the global namespace, in case the user (or someone) else decided to have a new operator.
Double-colon is used to prevent T::operator new() to be called (if
defined).
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.