Can I prevent invoking destructor before overloaded delete? - c++

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.

Related

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.

Is there any way in c++ to make sure at compile time a non-template function is not used anywhere?

So I know I can see whether a function is called either after compilation (using disassembly and -O0 usually) or at runtime by introducing an exception into it.
However I'm interested in making sure a particular function (in this case operator new) is never called from anywhere? I want to make sure I do not perform any dynamic memory allocation at compile time.
A warning would probably suffice that the function is used.
UPDATE:
A code example is here:
#include <functional>
#include <iostream>
// replace operator new and delete to log allocations
void* operator new (std::size_t n) {
std::cout << "Allocating " << n << " bytes" << std::endl;
return malloc(n);
}
void operator delete(void* p) throw() {
free(p);
}
class TestPlate
{
private:
int value;
public:
int getValue(){ return value; }
void setValue(int newValue) { value = newValue; }
int doStuff(const std::function<int()>& stuff) { return stuff(); }
};
int main()
{
TestPlate testor;
testor.setValue(15);
const std::function<int()>& func = std::bind(&TestPlate::getValue, &testor);
std::cout << testor.doStuff(func) << std::endl;
}
I would like to receive an error whenever anything tries to use operator new. In this case the internals of std::function try to use operator new.
In general I want to make sure that my program does not perform any sort of dynamic memory allocation. I want to be sure of that at compile time.
If you want to be 100% sure a function is never called, then delete it. Then the compiler and linker will yell at you if something did indeed try to call it.
How about class-specific operator new and make it private? I.e.:
class MyClass {
...
private:
void * operator new(size_t size);
};
Then when trying to call new MyClass, the compiler should complain.
EDIT:
So another solution might be to make the call of operator new ambiguous. For example:
// make the call to operator new ambiguous
struct Invalid {};
void * operator new(size_t size, Invalid inv = Invalid());
After doing this, every call of the operator new will be ambiguous (because the second parameter has a default value, so the compiler will not know, which version to use). And with your example, it then fails to compile the std::function template.

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.

How can I overload the operator& in C++

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.

Why operator new function - placement form ok in class level?

We know from c++ 11(also true in c++98/03 standard) standard(see below), we cannot try to replace the operator new function - placement form in global space as it has already been defined.
18.6.1.3 Placement forms [new.delete.placement]
These functions are reserved, a C++ program may not define functions that displace the
versions in the Standard C++ library (17.6.4). The provisions of
(3.7.4) do not apply to these reserved placement forms of operator new
and operator delete.
This has been proven by point 2> in the snippet below, compile error as expected.
But I can still override the placement new in class level,that works fine, see point (2) in snippet below. Why is that? Shouldn't compile should try to prevent (2) as well according to standard ???
See my snippet below:
class Test
{
public:
Test(int i):m_i(i) { cout << "Test::Test()" << endl; }
~Test() { cout << "Test::~Test()" << endl; }
//(1)class level override placement new
void* operator new (std::size_t size) throw (std::bad_alloc) {
cout << "My class level new" << endl;
return malloc(size);
}
//(2)class level override placement new
void* operator new (std::size_t size, void* ptr) throw() {
cout << "My class level non-throwing placement new" << endl;
return ptr;
}
private:
int m_i;
};
//<1>global replacement for operator new - single object form
void* operator new (std::size_t size) throw (std::bad_alloc) {
cout << "My global new" << endl;
return malloc(size);
}
//<2>global replacement for operator new - replcement form
//NB. This is a attempt that definitely fails according to c++ stadnard:
//does get compile error: error: redefinition of 'void* operator new(std::size_t, void*)'
/*
void* operator new (std::size_t size, void* ptr) throw() {
cout << "My global non-throwing placement new" << endl;
return ptr;
}
*/
int main() {
Test* p = new Test(1);
delete p;
cout << "" << endl;
void* mem = operator new(sizeof(Test));
Test* p2 = new(mem) Test(1);
p2->~Test();
operator delete (mem);
return 0;
}
Below is output as expected:
My class level new
My global new
Test::Test()
Test::~Test()
My global new
My class level non-throwing placement new
Test::Test()
Test::~Test()
==================================================================================
Further clarification for my question:
18.6.1.3 Placement forms These functions are reserved, a C++ program may not define functions that displace the versions in the
Standard C++ library (17.6.4). The provisions of (3.7.4) do not apply to these reserved placement forms
of operator new and operator delete.
This explains the expected compile error at point <2> in my snippet, so this one is ok.
But why I can displace the placement forms in the class level at point (2) inside the class clarification?
ยง18.6.1.3 lists the following forms:
void* operator new(std::size_t size, void* ptr) noexcept;
void* operator new[](std::size_t size, void* ptr) noexcept;
void operator delete(void* ptr, void*) noexcept;
void operator delete[](void* ptr, void*) noexcept;
The rule that "a C++ program may not define functions that displace the versions in the Standard C++ library" applies only to these four function declarations, which are not in any namespace. If you make your own version in a class or a namespace, that's fine.
In fact, sometimes you have to provide your own placement new. If you declare a normal operator new in your class, it will hide the placement new provided by the standard library, and you'll need to add your own placement new in the class if you ever want to use the new (ptr) T(...) syntax.
This simply provides a guarantee that the call ::new (ptr) T(...) is guaranteed to behave like the standard placement new. (Note the :: prefix.)