We have a base class A, class B derived from A.
Now class B is allocated using placement new operator.
As a part of my code, I have added class C inside class A
Now the placement new just uses malloc of sizeof class B and does not take into account class C.
Class C constructor is called inside the Class B constructor. ( this is my suspect )
I want to know if thats correct. Or do we add the size of class C in the placement new allocation?
if we add up the memory, how do we call the constructor for class C, it would allocate the memory again?
card.h {
class Card
{
private:
char hwModel; // HW/FW model and rev are stored in the
// database to detect change of card type
char hwRev;
char serialNum[EM_CARD_SERIAL_NUM_SIZE];
char fwModel;
char fwRev;
>>>>
public:
class IssuResource *ptrIssuResrc;
void *operator new(size_t size, void *objP) {size = size; return objP;};
// overload the new operator
void operator delete(void *objP) { objP = objP;};
// overload the delete operator
Card();
}
chopperCard.cpp
// Allocate Memory and Create Card Object
/* sa_ignore */
buf = (UINT32 *)malloc(sizeof(CardChop));
if (buf == NULL) {
emLogError(EM_INTERNAL_ERROR, __FUNCTION__,
"exit: failed to allocate %d bytes for card object\n",
sizeof(CardChop)
);
exit(1);
}
/* sa_ignore */
card = new (buf) CardChop(spa_issu_restart); --> placement new
}
Constructor for choppercard:
{
CardChop::CardChop (boolean is_issu_set) : Card()
{
issu_inprogress = is_issu_set;
if (is_issu_set) {
ISSUTRACE(4,"Issu state is SET\n");
dev_np37xx_update_issu_state(is_issu_set);
dev_set_issu_state(is_issu_set);
dev_dm_issu_state(is_issu_set);
dev_tigris_issu_state(is_issu_set);
dev_evros_issu_state(is_issu_set);
dev_evros1_issu_state(is_issu_set);
>>>
vtwin->fvt->set_gp_stat(vtwin, VTWIN_GP_STAT_APP_TRACE1,
CHOP_BG_INIT_FAIL);
// init Bourget device
initDevice((dev_object_t *)bourget);
vtwin->fvt->set_gp_stat(vtwin, VTWIN_GP_STAT_APP_TRACE1, CHOP_BG_INIT_AFTER);
ptrIssuResrc = new IssuResource();
}
Placement new will work JUST like operator new without placement, except that it uses the supplied address rather than allocating from the heap. Since neither forms of operator new will in itself call the actual constructor, the construction is exactly the same either way - the compiler calls the object constructor something like this
T *p = new T;
becomes (not valid syntax, and T::operator new may become ::operator new):
T *p = T::operator new(sizeof(T)); p->T();
with placement, it's nearly the same:
T *p = new(somewhere) T;
becomes (not valid, as above):
T *p = T::operator new(sizeof(T), somewhere); p->T();
If you have something like this:
class C { ... };
class A
{
...
C c;
};
class B: public A
{
...
}
then C's constructor will be called automatically when the constructor of B is called. (And B's constructor will automatically call A's constructor)
The value returned from sizeof includes the sizes of all the bases and members. There is no other concept of size to confuse things.
It looks like the code is excessively complicated. What you are doing with malloc is simply reinventing the default behavior of new.
This does the same thing, but simpler:
card = new CardChop(spa_issu_restart);
if (card == NULL) {
emLogError(EM_INTERNAL_ERROR, __FUNCTION__,
"exit: failed to allocate %d bytes for card object\n",
sizeof(CardChop)
);
exit(1);
}
If using the global, default operator new, you should also remove the operator delete overload.
In fact, the best practice with placement new is not to use delete at all. (Note that you have defined operator delete to do nothing.) The better way is to use a pseudo-destructor call, which looks like
card_ptr->~CardChop(); // execute destructor but no delete
free( card_ptr ); // release placement memory a la delete
Also, note that exit is a potentially unsafe way to terminate the program as it doesn't destroy local objects. Consider throwing an exception instead.
Related
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;
}
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.
I am trying to understand how the operator new can be overloaded and got this from the research I did online.
The new operator overload function takes in a size_t type. However in my main I am calling it using new Dummy(). From my understanding Dummy gets implicitly converted to size_t correct ? then what happens to () after Dummy ? shouldn't that result in an error ?
void* operator new(size_t sz)
{
void* m = malloc(sz);
std::cout<<"User Defined :: Operator new"<<std::endl;
return m;
}
class Dummy
{
public:
Dummy()
{
std::cout<<"Dummy :: Constructor"<<std::endl;
}
~Dummy()
{
std::cout<<"Dummy :: Destructor"<<std::endl;
}
};
int main()
{
Dummy * dummyPtr = new Dummy();
}
There are 2 things involving new keyword:
First you have the new operator, there are different overloads defined by the standard and you can override them or create your new ones. It's responsibility is allocating memory of N size and returning a void* to it. You can even create your own new operator that allocates memory and gets an extra parameter like this:
void* operator new(size_t sz, char x) // x is a placement param
{
std::cout << "User Defined :: Operator new" << std::endl;
return ::operator new(sz); // standard new
}
auto* x = new('*') int(234); // our overload
But wait a second, how does the new operator get the size of the type we want to instantiate??
Our friend the new expression just entered the game!
Think about the new expression like some syntactic sugar for calling the new operator. It has this structure:
new(placement_params) type+initializer
it means that for new int(22) the expression will be new(no placements) int + copy_initializer(22) and it will internally call the new operator passing the size of the type.
New operator will return a void* that points to the memory that it just allocated and the right-size of the new expression will initialize that memory. In this example calling the copy initializer
new is a language construct and not a regular function to it has special syntax and conveniences regarding its usage. There's differences between a new expression and operator new
The following both construct a Dummy but one uses local storage and the other uses dynamic storage. So in both cases Dummy() is part of the constructor call and, in the second case, not tied directly to new.
auto d1 = Dummy();
auto d2 = new Dummy();
Here the new expression both allocates space and constructs the Dummy in that space using the supplied constructor and arguments. The amount of space is determined by the compiler via sizeof Dummy.
When you overload the default operator new, it will use your user-defined function to do the allocation, but not the construction (that is done by the new expression).
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
I have a point in my mind which I can't figure out about new operator overloading.
Suppose that, I have a class MyClass yet MyClass.h MyClass.cpp and main.cpp files are like;
//MyClass.h
class MyClass {
public:
//Some member functions
void* operator new (size_t size);
void operator delete (void* ptr);
//...
};
//MyClass.cpp
void* MyClass::operator new(size_t size) {
return malloc(size);
}
void MyClass::operator delete(void* ptr) {
free(ptr);
}
//main.cpp
//Include files
//...
int main() {
MyClass* cPtr = new MyClass();
delete cPtr
}
respectively. This program is running just fine. However, the thing I can't manage to understand is, how come new operator can be called without any parameter while in its definition it has a function parameter like "size_t size". Is there a point that I am missing here?
Thanks.
Don't confuse the "new expression" with the "operator new" allocation function. The former causes the latter. When you say T * p = new T;, then this calls the allocation function first to obtain memory and then constructs the object in that memory. The process is loosely equivalent to the following:
void * addr = T::operator new(sizeof(T)); // rough equivalent of what
T * p = ::new (addr) T; // "T * p = new T;" means.
(Plus an exception handler in the event that the constructor throws; the memory will be deallocated in that case.)
The new-expression new MyClass() is basically defined in two steps. First it calls the allocator function, which you have overloaded, to get some allocated memory. It passes the size of the type MyClass to that allocator function, which is why the size_t argument is required. After this, it constructs an object in that allocated memory and returns a pointer to it.
The compiler knows the size of your class. Basically, it's passing sizeof(MyClass) into your new function.