In a situation where I want to avoid dynamic memory allocations, I'm replacing the new operator with a process that essentially uses the memory of some statically allocated object (the Storage class below). You can see a minimum working example below:
#include <cassert>
#include <iostream>
struct Object {
Object() { std::cout << "Creating a new object\n"; }
static void *operator new(size_t);
static void operator delete(void *p);
};
static struct {
Object where;
bool allocated = false;
} Storage; // 1
void *Object::operator new(size_t) {
assert(!Storage.allocated);
auto p = ::new (&Storage.where) Object; // 2
Storage.allocated = true;
return p;
}
void Object::operator delete(void *p) {
assert(Storage.allocated);
static_cast<Object *>(p)->~Object();
Storage.allocated = false;
}
int main() { Object *obj = new Object; } // 3
My question has to do with the number of calls to the constructor. When I run the above program, I expect to call the constructor twice (marked as 1 and 2 in the comments above) but the output I get is:
Creating a new object
Creating a new object
Creating a new object
Why is the constructor called thrice? I'd only expect constructor calls, by the static object and the call to placement new. I tried tracing the code with gdb, but it makes no sense to me, since position //3 is where the third call to the constructor originates.
The reason I want to know is because a case has emerged, where this extra constructor call causes unwanted side-effects; up until now, this extra call was unnoticed.
For some odd reason, your operator new calls the constructor when it should just allocate memory. This means that the call to new winds up calling the constructor of Object twice. There is one call in operator new and another call in main.
You probably want this:
void *Object::operator new(size_t) {
assert(!Storage.allocated);
Storage.allocated = true;
return reinterpret_cast<void *> (&Storage.where);
}
Imagine if the constructor took an integer parameter and the line in main looked like this:
Object *obj = new Object(7);
How would operator new know how to properly construct the object? That's not where you're supposed to do that!
Object *obj = new Object; does two things:
Allocates memory by calling operator new
Calls the constructor.
Your operator new calls the constructor as well, so the constructor is called twice by this statement (and once for the global variable initialization).
Note that delete is the same. delete obj; does two things:
Calls the destructor.
Deallocates memory by calling operator delete
Your operator delete shouldn't call the destructor either, because then the destructor is called twice.
Related
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.
C++20 has added destroying form of operator delete distinguished by the std::destroying_delete_t parameter. It causes delete expression to no longer destroy the object prior to invoking operator delete.
The intention is to allow customization of deletion in a way that depends on the object's state, before explicitly invoking the object's destructor and deallocating memory.
However, it isn't clear to me if, when implementing such an operator, I'm actually required to destroy the object. Specifically, am I allowed to have a pool of static objects, and give them out to users who can subsequently treat them as-if they were dynamically allocated? Such that delete expression executed on the object will merely return it to the pool without destroying it. For example, is the following program well-defined?
#include <new>
struct A {
virtual ~A() = default;
};
// 'Regular' dynamically allocated objects
struct B : A {
static A* create() {
return new B();
}
private:
B() = default;
};
// Pooled, statically allocated objects
struct C : A {
static A* create() {
for (auto& c: pool) {
if (!c.in_use) {
c.in_use = true;
return &c;
}
}
throw std::bad_alloc();
}
private:
static C pool[3];
bool in_use = false;
C() = default;
void operator delete(C *c, std::destroying_delete_t) {
c->in_use = false;
}
};
C C::pool[3];
// Delete them identically via the common interface.
void do_something_and_delete(A* a) {
delete a;
}
int main() {
do_something_and_delete(B::create());
do_something_and_delete(B::create());
do_something_and_delete(C::create());
do_something_and_delete(C::create());
}
The purpose of destroying delete operators, as defined by its proposal, is to effectively deal with the ability to create and destroy objects whose deallocation and destruction needs access to the object, for one reason or another. It does this by preventing the automatic invocation of the object's destructor when you invoke delete on objects with a destroying operator delete function. The (still live) object is then passed to the destroying operator delete, so that it can do the deallocation and destruction business.
Its purpose is not to make the statement delete whatever; lie to the user about what this statement accomplishes. But as a consequence of one of the use cases of the feature (virtual destructors without virtual functions), the feature can be (ab)used to lie to the user.
The lifetime of an object ends when its destructor is entered (or when the storage is reused/released). If a destroying operator delete is (ab)used to prevent calling that destructor, then deleteing the object will not end its lifetime.
But lying to the user is a bad idea and you shouldn't do it.
I've seen a few places that show how to overload the global new function for allocations. What I would like to do is to have any call to 'new' call my function, which simply wraps the C++ standard 'operator new' and tracks memory usage. But I have a problem of not knowing how to construct the object because the type of the object is not available in the function:
void* operator new (std::size_t size)
{
// I don't know what to construct
}
struct MyClass{ int members[8];}
new MyClass; // I'd basically like to wrap the standard 'new' function allocator.
You are not supposed to construct an object inside of an overloaded operator new, only allocate raw memory of the requested size and return a pointer to it. The object’s constructor will be called on the returned memory after the operator new exits.
A new expression calls operator new specifying the size of the type, then calls the type’s constructor on that memory, and then returns a pointer to the object that was created.
Thus, an expression like new MyClass in your example is roughly equivalent (not exactly) to this:
//MyClass *cls = new MyClass;
void *mem = :: operator new (sizeof(MyClass));
MyClass *cls = static_cast<MyClass*>(mem);
cls->MyClass();
And the converse is true for the delete expression, which calls the type’s destructor, and then calls operator delete to deallocate the raw memory, eg:
//delete cls;
cls->~MyClass();
:: operator delete (cls);
It seems you're looking for a Factory function. A factory is a dedicated function (or even a class) that produced instances of a class.
E.g.
#include <memory>
struct MyClass { int members[8]; };
std::unique_ptr<MyClass> MyClassFactory() {
auto inst = std::make_unique<MyClass>();
// assign some stuff to members
return inst;
}
Maybe the question is basic but I didn't found answer for that.
I will give the some examples (when Object has destructor), and I will glad to understand what happens in each one:
1)
int f (){
Object *p=new Object();
int something=5;
return something;
}
I think it would not call the destructor, but someone told me that if the function has return then the destructor will be called.
2)
Object & f (){
Object *p=new Object();
return *p;
}
How about now? is it connected to the object instance we return?
if 1) is not calling detractor please confirm that 3) is not calling the destructor (I still think it will not, but confirming)
3)
int f (){
for(int i=0; i<10; i++){
Object *p=new Object();
}
int something=5;
return something;
}
If 1) is calling the destructor: if 3) was void function, does the destructor
will be called (I again think not).
In case #1, the destructor is NOT called, because the object exists in dynamic (heap) memory, so it will not be destructed until delete is called on it. Every new needs a matching delete.
The destructor WOULD be called if the object were created in automatic (stack) memory instead, eg:
int f() {
Object p; // <-- no 'new'
int something=5;
return something;
} // <-- ~Object() is called here
In case #2, the destructor of the object pointed to by p is NOT called, and the return statement is returning a reference to the same object that exists in dynamic memory.
If the function returned an Object by value instead of by reference, then the return statement would make a copy, and the copy WOULD be destructed (but not the original!) when the caller is done using the returned object, eg:
Object f() {
Object *p=new Object();
return *p; // <-- copy made here
}
f(); // <-- ~Object() for the return value
// is called when the ';' is reached
In case #3, again the objects being created in dynamic memory are NOT destructed automatically upon return.
In all three cases, you can use std::unique_ptr to provide automatic memory management of dynamic objects, eg:
int f() {
std::unique_ptr<Object> p(new Object);
int something=5;
return something;
} // <-- ~unique_ptr() is called here
std::unique_ptr<Object> f() {
std::unique_ptr<Object> p(new Object);
return std::move(p);
} // <-- ~unique_ptr() for p is called here
f(); // <-- ~unique_ptr() for the return value
// is called when the ';' is reached
int f() {
for(int i=0; i<10; i++) {
std::unique_ptr<Object> p(new Object);
} // <-- ~unique_ptr() is called here
int something=5;
return something;
}
Absolutely not. C++ is not garbage-collected like Java.
Every new has to be balanced with a delete, and you need to pass the pointer you get back from new to that call to delete. (More formally that pointer has to be the same type too, or polymorphically related).
Fortunately, C++ does provide smart pointer classes like std::unique_ptr that wrap the delete call in its destructor.
I am learning the C++ placement new by the following code.
class Cell {
public:
Cell() {
printf("default constructor by %s\n", __func__);
}
Cell(int ina) : a(ina) {
printf("customized constructor.\n");
}
~Cell() {}
void* operator new(size_t); // Operator new.
void* operator new(size_t, Cell*p) {
return p;
}
private:
int a; // tmp variable.
};
// Global variable.
Cell global_cell;
void* Cell::operator new(size_t size) {
printf("start running the placement new\n");
Cell* ptr = new (&global_cell) Cell;
printf("the cell pointer is %p and the global address is %p\n", ptr, &global_cell);
return ptr;
}
int main() {
printf("====\n");
Cell *ptr = new Cell;
printf("====\n");
}
Here is the output I got:
default constructor by Cell
=====
start running the placement new
default constructor by Cell
the cell pointer is 0x60107c and the global address is 0x60107c
default constructor by Cell
=====
I know the first "default constructor" comes from the initiation of global_cell. But why I got two "default constructor" after that? Am I missing something about the placement new? Also, how can I implement the placement new with the second non-default constructor which takes an input integer?
new (&global_cell) Cell
in your operator new overload is one default construction, new Cell in mainis the other.
operator new is only supposed to allocate memory, not construct an object; the relevant constructor is called automatically afterwards.
Using placement new with your non-default constructor isn't very complicated:
new (&global_cell) Cell(2)
(That is, there's no difference to "regular" new.)
You're implementing the custom operator new for the class in the wrong way.
operator new for a class should just provide the raw memory where to put the instance, not create an object. Placement new instead initializes an object (using the default constructor in your case because you specified no parameters).
If you want to use placement new and passing parameter just write
new (memory_address) MyObject(arg1, arg2);
but note that using placement new is sort of an alternative to defining a custom operator new for the class. In the latter you just call normal allocation with
new MyObject(arg1, arg2);
to use your custom allocator (that however should just provide enough and properly-aligned memory).
You get them when you call "new Cell":
Cell *ptr = new Cell;
Cell* ptr = new (&global_cell) Cell;
After operator new is called, constructor is always called