How can I overload the operator& in C++? I've tried this:
#ifndef OBJECT_H
#define OBJECT_H
#include<cstdlib>
#include<iostream>
namespace TestNS{
class Object{
private:
int ptrCount;
public:
Object(): ptrCount(1){
std::cout << "Object created." << std::endl;
}
void *operator new(size_t size);
void operator delete(void *p);
Object *operator& (Object obj);
};
void *Object::operator new(size_t size){
std::cout << "Pointer created through the 'new' operator." << std::endl;
return malloc(size);
}
void Object::operator delete(void *p){
Object * x = (Object *) p;
if (!x->ptrCount){
free(x);
std::cout << "Object erased." << std::endl;
}
else{
std::cout << "Object NOT erased. The " << x->ptrCount << "references are exist."
<< std::endl;
}
}
Object *Object::operator& (Object obj){
++(obj.ptrCount);
std::cout << "Counter is increased." << std::endl;
return &obj;
}
}
#endif
Tne main function:
#include<iostream>
#include"Object.h"
namespace AB = TestNS;
int main(int argc, char **argv){
AB::Object obj1;
AB::Object *ptrObj3 = &obj1; // the operator& wasn't called.
AB::Object *ptrObj4 = &obj1; // the operator& wasn't called.
AB::Object *obj2ptr = new AB::Object();
}
The output result:
Object created.
Pointer created through the 'new' operator.
Object created.
My operator& wasn't called. Why?
You are currently overloading the binary & operator (i.e. bitwise AND). To overload the unary & operator, your function should take no arguments. The object it applies to is that pointed to by this.
Object *Object::operator& (){
++(this->ptrCount);
std::cout << "Counter is increased." << std::endl;
return this;
}
The sftrabbit answer is correct about syntax, but beware that what you are doing with new and delete is not congruent.
the new and delete operator work on raw memory, not on constructed object.
When you do A* p = new A ...
operator new is called and ...
the object A constructor is than called over the returned memory address and ...
finally the address is converted into A* and given to p.
Similarly, when you do delete p ...
The A destructor is called and...
The memory address is given to operator delete to be given back to the system.
In both the situation the state of A object instance (the value of its members) is undefined:
inside the operator new whatever thing you do, will be overwritten by the subsequent constructor call. In case the constructor does not initialize something, the standard says it's value is undefined (and not granted to be the same you can set in new).
inside the operator delete whatever thing you do is done on an already dead object (and what you found inside it is not granted to be the "last live state".
In any case the object dies when you call delete. You cannot "save it from dead" during operator delete (that's called after destruction). It's purpose is to place the tombstone, not to reanimate the cadaver.
Related
I had a situation where I wanted to import a call after another call from the calling function. I decided to override a virtual destructor for the purpose:
#include <iostream>
struct type {
virtual ~type() {
std::cout << "ordinary" << std::endl;
}
void method() {
struct method_called : type {
virtual ~method_called() override {
std::cout << "method called" << std::endl;
}
};
this->~type();
new (this) method_called{};
}
};
int main() {
std::cout << "ordinary expected" << std::endl;
{
type obj;
}
std::cout << "method expected" << std::endl;
{
type obj;
obj.method();
}
std::cout << "method expected" << std::endl;
type* pobj = new type{};
pobj->method();
delete pobj;
}
It seems the overridden destructor is called only using dynamic allocation. Is this intended?
GCC godbolt.
this->~type();
Any dereference of any pointer pointing to the object or variable referring to the object that exists prior to this line is undefined behavior once you do this.
This includes the automatic storage destructor.
To avoid undefined behaviour in main after doing this, you'd have to call exit or similarly never return from the scope where the variable exists.
By the time the destructor is finished, the objects lifetime is over. Almost any use of the object after that triggers UB. You can reuse the storage:
new (this) method_called{};
This creates an distinct object in the storage that this refers to. If this storage has sufficient alignment and size, doing so is fine. It is extremely tricky to get right, because one of the few ways to safely get a pointer to this newly created object is by recording the return value to placement new like this:
auto* pmc = new (this) method_called{};
you don't do that.
{
type obj;
obj.method();
}
this is undefined behavior. The standard does not restrict what the program produced by your compiler does if this code is or would be executed at any point in your programs execution.
type* pobj = new type{};
pobj->method();
delete pobj;
so is this.
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.
I wonder how this code run specifically line 54 (line2 = line1) although there is no overloading for the assignment operator ?
It seems from the output that neither the copy constructor nor the normal constructor were called and surprisingly it gets output as expected 199 199
#include <iostream>
using namespace std;
class Line
{
public:
int getLength();
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr;
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength()
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main()
{
Line line1(199);
Line line2(1);
line2 = line1; // How this is executed ??!
cout << line1.getLength() << " " << line2.getLength() << endl ;
/*display(line1);
display(line2);*/
cin.get();
return 0;
}
What you have there is undefined behavior. You assign line2 = line1 but have no user-defined assignment operator, so you use the default one provided by the compiler. And the default one simply copies all the fields, which in your case includes an int*. That gives you two copies of the same int*, leaks the value that line2 previously pointed to, and eventually double-deletes the one line1 originally pointed to. The second delete of the same pointer, which occurs when line1 goes out of scope at the end of main(), invokes undefined behavior.
If you have a destructor which frees resources, you probably need an assignment operator too. See the Rule of Three: http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
But the best solution is to stop using raw pointers. Use a smart pointer and this problem will not occur in the first place, and you can omit your destructor.
In a situation like this, writing your own copy constructor, assignment operator and destructor should be your last resort, not your first reaction.
Your first reaction should usually be to use some pre-defined class that already handles these chores for you. In this case, changing from a raw pointer to a shared_ptr (for only one possibility) cleans up the code fairly quickly. Using it, the code ends up something like this:
#include <iostream>
#include <memory>
using namespace std;
class Line
{
public:
int getLength();
Line( int len ); // simple constructor
~Line(); // destructor
// copy constructor removed, because the one supplied by the
// compiler will be fine. Likewise the compiler-generated assignment
// operator.
private:
shared_ptr<int> ptr;
};
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
// Note the use of make_shared instead of a raw `new`
ptr = make_shared<int>(len);
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
// don't need to actually do anything--freeing is automatic
}
int Line::getLength()
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main()
{
Line line1(199);
Line line2(1);
line2 = line1; // uses compiler-generated assignment operator (which works)
cout << line1.getLength() << " " << line2.getLength() << endl ;
display(line1);
display(line2);
cin.get();
return 0;
}
Depending upon the situation, a unique_ptr might be a better fit than a shared_ptr. In this case, shared_ptr is probably easier to incorporate into the existing code though.
You might also want to read R. Martinho Fernandes' Rule of Zero blog post on this subject.
If no user-defined copy assignment operators are provided for a class type (struct, class, or union), the compiler will always declare one as an inline public member of the class.
This implicitly-declared copy assignment operator has the form T& T::operator=(const T&) if all of the following is true:
Each direct base B of T has a copy assignment operator whose parameters are B or const B& or const volatile B&
Each non-static data member M of T of class type or array of class type has a copy assignment operator whose parameters are M or const M& or const volatile M&
Otherwise the implicitly-declared copy assignment operator is declared as T& T::operator=(T&). (Note that due to these rules, the implicitly-declared copy assignment operator cannot bind to a volatile lvalue argument)
Copied from this article from CPPReference.
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.
I'd like to use boost.pool. It's okay if you don't know about it. Basically, it has two main functions, malloc() and free().
I've overloaded new and delete for my custom defined class test.
class test
{
public:
test()
{
cout << "ctor" << endl;
}
~test()
{
cout << "dtor" << endl;
}
void* operator new(size_t) throw()
{
cout << "custom operator new" << endl;
return _pool.malloc();
}
void operator delete(void* p)
{
cout << "custom operator delete" << endl;
_pool.free(p);
}
void show()
{
cout << _i << endl;
}
private:
int _i;
static boost::pool<> _pool;
};// class test
boost::pool<> test::_pool(sizeof(test));
When I create instance of test using new, constructor was not called but if I delete it, destructor was called. Why? and can I avoid it?
Can't reproduce, when added
#include <iostream>
#include <boost/pool/pool.hpp>
using namespace std;
(why do people omit such things that are necessary to make the code compile?!) and
int main()
{
test* p = new test;
delete p;
}
This is either a stripped-down and modified version that doesn't have that behavior or your compiler may be broken (which version is it?)
In any case your aim should be getting the constructor called, rather than getting destructor not called. Overloaded operator new just deals with raw memory allocation, the built-in new-expression should use that to obtain the memory and then call the constructor to create an instance there.
Edit: the only way I can reproduce your output is by circumventing the built-in new-expression:
test* p = static_cast<test*>(test::operator new(sizeof (test)));
Could it be because the global operator new is getting called? Anyways, just a comment about your class...
operator new and operator delete are always static (even if you don't write the keyword), so it's good practice to use static in the declaration.
You declared operator new with throw(), meaning that it won't throw. But you use a statement (iostreaming) that can throws. Maybe you should surround that with try/catch and create an std::nothrow_t version.