Reputation: 474
Suppose i have this sample code:
class A
{
public:
static void* operator new(size_t sz);
private:
int xA;
float yA;
};
class B : public A
{
private:
int xB;
float yB;
};
void* A::operator new(size_t sz)
{
void* ptr = (void*)new B();
return ptr;
}
int main()
{
B* b = (B*) new A();
// Use b ..
delete b;
return 0;
}
Here the constructors will be called in that order (tested in VS2012):
The first two constructors calls are because of the new B()
in the overloaded operator new function.
But then the A constuctor will be called again on the pointer returned by the function because the overloaded operator new is supposed to return a pointer to free memory (without creating the object), so the constructor is called again.
If i use the pointer b
in this example, is this undefined behaviour?
Upvotes: 1
Views: 251
Reputation: 153929
The code you posted has endless recursion, since you call
A::operator new
from within A::operator new
; class B
inherits the operator new
from A
.
Beyond that, you lie to the compiler, which results in undefined
behavior. After new A
, you have a pointer to an object whose
type is A
. You can legally convert its address to a B*
, but
all you can do with that B*
is convert it back to an A*
;
anything else is undefined behavior.
And it's not clear what you're trying to achieve with the new
B
in A::operator new
. The compiler will consider any memory
returned from an operator new
as raw memory; in this case, it
will construct an A
object in it, and from then on out, all
you have is an A
object. Any attempt to use it as a B
object is undefined behavior. (And of course, if you actually
need to destruct the B
created in A::operator new
, you can't
because you've overwritten it.
Finally: you don't have to declare operator new
as static
;
it implicily is, and it's idiomatic not to write the static
in
this case. Similarly, when assigning the results of new B
to
a void*
, the conversion is idiomatic, and it is idiomatic not
to make it explicit. (It's also best to avoid the C style
casts, since they hide too many errors.)
Upvotes: 1
Reputation: 208363
The contract of operator new
is just the memory allocation, the initialization is done later by the new-expression (by calling the constructor) or by program code if you call the operator directly.
What you are trying to do cannot be done, not like that. You could redesign to use a factory member function that would return a pointer to a B
object, for example...
Upvotes: 1
Reputation: 129374
In general , operator new()
should not CREATE an object, it should create space for an object. Your code will overwrite a B
object with an A
object, and then use it as a B
object, and yes, that would be "undefined" (probably covered in the docs under "casting an object to a different type that it wasn't originally created as).
This may appear to work in this particular case, but if the constructor of B
is more complex (e.g. there are virtual functions in B
), it would immediately fail to work correctly.
If you want to allocate memory for an object, you could do:L
void* A::operator new(size_t sz)
{
void* ptr = (void*)::new unsigned char[sz];
return ptr;
}
Now you are not calling two different constructors for the same object!
Upvotes: 1