How operator new calls the constructor of class? - c++

I know that, new operator will call the constructor of class.
But how it's happening, what is ground level techniques used for this.

Here is how I imagine it:
T* the_new_operator(args)
{
void* memory = operator new(sizeof(T));
T* object;
try
{
object = new(memory) T(args); // (*)
}
catch (...)
{
operator delete(memory);
throw;
}
return object;
}
(*) Technically, it's not really calling placement-new, but as long as you don't overload that, the mental model works fine :)

It's not really the new operator that calls the constructor. It is more the compiler that translate the following line:
MyClass * mine = new MyClass();
Into the following:
MyClass * mine = malloc(sizeof(MyClass)); // Allocates memory
mine->MyClass(); // Calls constructor
With other error handling code that other answers have noted.

The compiler generates machine code for that. When the compiler sees
CSomeClass* object = new CSomeClass();
(new statement) it generates code that calls the appropriate operator new() (which allocates memory), calls the right constructor, calls destructors of all fully constructed subobjects in case of exception, calls operator delete() in case an exception occurs during construction. All this is done by extra machine code generated by the C++ compiler for that simply looking statement.

Related

C++ custom delete

Let's say we have the following code:
class MyType
{
public: int x;
}
MyType* object = new MyType();
delete object;
Is there a possible to check if object has specific value of x before deletion?
For example, if object.x is odd number, the object should not be free from memory after delete is called. In a few words to make a custom delete for this class where we can choose when the object can be free at operator delete call.
What is the real issue you are trying to solve?
To begin with, this Q&A is a good lesson to the common scenario in C++ of:
The language allowing you to do something, but just because you can doesn't mean you should.
These scenarios are commonly run into when trying to solve an XY problem.
In this particular case, instead of trying to overload operator delete (solving the Y problem, to much confusion of the clients of MyType) you are likely looking for something entirely different (the X problem), say a resource manager that take responsibility of MyType resources w.r.t. if and when they should be deleted (or not), based on e.g. object traits (such as oddness of a data member). See e.g. #Ayxan Haqverdili's answer for a minimal example.
A look at theoretically solving the misidentified Y problem
Don't do this, ever, for this kind of use case.
You can overload operator delete (as well as operator delete[]), by defining it as a static member function of the class for which you want to overload it (lookup precedence by lexical scope). As pointed out in the comments, whilst overloading the usual deallocation functions is legal, trying to conditionally allow for it to be called more than once is not:
struct MyType final {
int x;
static void operator delete(void *p) {
if (static_cast<MyType *>(p)->x % 2 == 1) {
::operator delete(p);
}
}
};
int main() {
MyType *object = new MyType{42};
delete object; // Not DEALLOCATED.
// Underlying object DESTRUCTED, however.
// Extremely confusing.
++(object->x);
delete object; // UB: destructor for underlying object called twice.
}
as per [expr.delete]/6 [emphasis mine]:
If the value of the operand of the delete-expression is not a null pointer value and the selected deallocation function (see below) is not a destroying operator delete, the delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted.
As a second attempt (emphasis: don't ever go down this road), we could avoid the destructor being called (only calling it conditionally) by overloading and abusing the (new as of C++20) class-specific destroying deallocation functions:
#include <iostream>
#include <new>
struct MyType final {
int x;
static void operator delete(MyType *p, std::destroying_delete_t) {
if (p->x % 2 == 1) {
p->~MyType();
::operator delete(p);
}
}
~MyType() {
std::cout << "\ndtor";
}
};
int main() {
MyType *object = new MyType{42};
delete object; // Neither deallocated nor underlying object destructed.
++(object->x);
delete object; // Destructed and deallocated.
}
Afaict this program is well-formed, but it does abuse the new destroying delete overloads. Clang does emit a -Wmismatched-new-delete warning, which is typically a hint for UB, but it may be inaccurate here.
Anyway, this seems like a good place to stop the fruitless journey of addressing this particular Y problem.
Yes:
if (object->x % 2 == 1)
delete object;
Note that raw pointers should be used rarely and with a lot of care.

Is it valid to call destructor on 'this' and then assign a new value to 'this'?

Suppose I'm implementing some class A that has a clear() method that should set the object state to the "brand new" state as if it has just been created with a constructor:
I should free all the resources that the current object is using (exactly the same thing A::~A() does),
and then I should initialize those resources again (exactly the same thing A::A() does).
So my initial idea was as follows:
void A::clear() {
this->~A();
*this = A();
}
However, I was told that this code causes UB since I cannot dereference this after calling its destructor. But at the same time I was told a better idea as well: if we use placement new, there is no dereferencing, so this actually might work:
void A::clear() {
this->~A();
new (this) A();
}
This feels extremely uncomfortable and as error-prone as it gets... So is this code actually valid?
is this code actually valid?
Your code is valid. It's also a rather unusual approach to merely change the object's value.
The assignment operator alone, if implemented correctly, will achieve this.
void A::clear() {
*this = A();
}
If this code does not work as expected, your assignment operator has been incorrectly implemented.

Not able to create the object by new if new operator is overloaded and constructor is private

Can any body explain why i am not able to create the object using new if it is overloaded and constructor is private.
class A
{
A();
A(A const &obj);
A& operator =(A const &obj);
public:
void * operator new(Size_t size)
{
void * p = malloc (size);
return p ;
}
};
int main ()
{
A * p = new A() /*gives compile time error, saying constructor
is private.But cant we access private function from class
public function . as operator new is public function of class.*/
return 0;
}
Possibly you are conflating a new-expression with operator new.
An operator new is an allocation function, with a confusing name. It should better have been called _alloc or some such.
A new-expression
calls the allocation function, passing any specified arguments.
if that succeeds, calls the class constuctor with specified arguments.
Here the relevant constructor must be accessible.
if that fails, cleans up by deallocating memory (in the case where the allocation function has user defined arguments, a corresponding user defined deallocation function is called with the originally specified custom allocation function arguments).
In short, a new-expression guarantees that if you have fulfilled your obligations, then you will either have an initialized object at hand, or an exception with no memory leak.
One way to not fulfill your obligations is to defined a custom allocation function with no custom deallocation function. Then in the last bullet point above you get no cleanup, and hence a memory leak. But other than that, a new-expression is almost like a database transaction, it guarantees all-or-nothing.
Constructor is called after operator new. As you can see, in operator new you are only using malloc to allocate raw memory. Afterwards, default constructor is called to initialize class members. So new A() calls both, operator new and constructor, constructor is private, so you cannot access it, and thus compiler won't allow it.

Copy Constructor classes

Here is my piece of code, please help me understand how to get the copy constructor correct. My class has no copy constructor written for it
test(cosnt test&obj){
////////something
}
But yet when I attempt to make a copy such as test t2(t1); it appears to be copied correctly! Can you please explain to me the reason that the copy seems to work even without an explicit copy constructor?
#include <iostream>
using namespace std;
class test{
int *ptr;
public:
test(int t=0){
ptr=new int;
*ptr=t;
}
void increment(){
(*ptr)++;
}
void display(){
cout<<*ptr<<endl;
}
};
int main(){
test t1;
t1.display();
t1.increment();
t1.display();
test t2(t1);//copy constructor works fine!
t2.display();
t1.increment();
t1.display();
t2.display();
}
C++ is so amazing that when you don't define a copy constructor, move constructor, copy assignment and move assignment for a class, the compiler will have to define them for you (the Standard says so). Of course you can delete them via:
func() = delete;
So for example, if you want to delete the implicit copy constructor in your example you would declare:
test(const test&) = delete;
and as you can see your code won't no longer compile.
The behavior of the implicit copy constructor is the one you would expect: it will copy construct each member of the class to the the other object. In this case it will copy construct the pointer value (not the pointed value), effectively make the two object share the same pointer.
Now, your program is leaking memory right? You have called new but no delete. Let's say you want to clean your resources up by inserting:
delete ptr;
in the destructor (it's a simplified version, of course you would need to define at least a proper move assignment and move constructor). You know what will happen? A nice and beautiful runtime error, telling you that the pointer you are trying to free has not been allocated. The reason why that is, is that both your objects (t1 and t2) destructors a will be called and they will both delete the same pointer. The first correctly and the second erroneously.
For this reason a Rule of three (now Rule of Five) has been established in the C++ community. But you know what? There's even a better rule which is called Rule of Zero. To sums it up (but you should really read about it) it says: don't do RAII yourself. I'd suggest you to follow the latter.
Now, let's discuss a little a bit of new. I'm sure you know this, but I'm here to prevent future damages: you don't need to use new at all in C++. Not anymore, in most cases.
Most of the things pointers once did (optional parameter, pass array by pointer, copyable reference, etc..) has now been "deprecated" (not in the literal sense: they are still there) in favor of sexier approaches (namely boost:optional/std::optional, std::array/std::vector, std::reference_wrapper). And even when all those fails to give you what you need, you can still use std::shared_ptr and std::unique_ptr.
So, please, don't use naked new pointers. Thanks.
If you did not define the copy constructor yourself then the compiler implicitly defines it instead of you. This copy constructor makes member-wise copies of class data members.
Relative to your example of code the implicitly defined copy constructor will copy data member ptr. As the result two or more objects can refer to the same memory.
Your class also needs destructor and the copy assignment operator.
These three specail functions can look the following way for your class
test( const test &rhs ) : ptr( new int( *rhs.ptr ) )
{
}
test & operator =( const test &rhs )
{
if ( this != &rhs )
{
int tmp = new int( *rhs.ptr );
delete ptr;
ptr = tmp;
}
return ( *this );
}
~test()
{
delete ptr;
}
You did not define a copy constructor. Like #jrok said, the compiler-generated default copy constructor only does shallow member-wise copy.
Your copy constructor can look something like:
public:
test(const test& t)
{
ptr = new int;
*ptr = *t.ptr;
}
BTW, you might want to define a destrcutor too to prevent memory leak.
~test()
{
delete ptr;
}

Global new operator call syntax

Why the function with this signature
void* operator new (std::size_t size);
Cant be called in code like this
void* mem = new(100);
But rather it must be called like this
void mem = ::operator new(100);
Keyword new and operator new are different things.
Keyword new does:
Call operator new to allocate the memory. It can be overloaded for the type being allocated. Keyword new accepts optional arguments that get passed to operator new, this allows for placement new and non-throwing new syntax, see #include <new>.
Invoke the constructor of the object.
If the constructor throws, invoke the corresponding operator delete to free the memory. Note that if that operator delete is not accessible (not public), then new fails at compile time because operator delete cannot be called if the constructor throws and memory would be lost.
Keyword new cannot be overloaded, it always does these steps. This is operator new from step 1 what can be overloaded, normally along with operator delete from step 3.
In other words, X* p = new X(a, b, c); under the hood does something like (pseudo code):
X* p = static_cast<X*>(X::operator new(sizeof(X))); // 1. allocate memory
try {
p->X(a, b, c); // 2. invoke the constructor
}
catch(...) {
X::operator delete(p); // 3. free the memory if the constructor throw
throw;
}
In the above, if X does not overload its operator new, it is the global ::operator new that gets called. Note that X::operator new is implicitly static if overloaded.
There is a profound syntactical reason for this: placement new. With placement new, you can call a constructor without allocating memory for it. It's syntax is this:
#include <new>
Foo* foo = new(bufferPointer) Foo();
Obviously, part of this is the precise syntax you tried to call ::operator new()...