overloading new, then using placement new.

Started by
17 comments, last by Enigma 17 years, 12 months ago
I'm trying to call a placement new on an object that has it's new overloaded. It seems that somehow the "new" function used in the placement new must be different then the normal new, right? Because as soon as I define a new default operator new, I get errors, even if the new is the same syntax as the global default new.

#include <new>

// Dummy class, ignore.
class Bar {
	int m_y;
};

class Foo {
  public:
	Foo() {}
	~Foo() {}

	//void* operator new(size_t size, void* place) { return place; } // <----- THIS FIXES THE BUG. DO I HAVE TO DO THIS?
	//void* operator new(size_t size, Bar *bar) { return malloc(size); }
	void* operator new(size_t size) { return malloc(size); }   // <------- THIS IS THE CAUSE OF THE BUG.
	void operator delete(void* data, Bar *bar) { free(data); }

  private:
	int m_x;
};

int main() {
	void* raw = malloc(sizeof(Foo));
	// Allocate the raw memory to be used in the placement new.

	Foo* p = new(raw) Foo();
	// Attempt the placement new. <----- THIS IS WHERE THE BUG SHOWS.

	p->~Foo();
	// Placement delete.

	free(raw);
	// Remove the memory.

	return 1;
}

Quote: Build Output (MSVC++ 2005 Express Edition.) error C2660: 'Foo::operator new' : function does not take 2 arguments
Do I really need to define
  void* operator new(size_t size, void* place)
as a function that will not be called when placement new is used? Man, why can't we just call Foo->Foo()... Thanks for all assistance.
Advertisement
Quote:
Do I really need to define

void* operator new(size_t size, void* place)

as a function that will not be called when placement new is used?

What do you mean? It *will* be called if you use placement new.
Quote:Man, why can't we just call Foo->Foo()...
If you want to reinitialize an object, why not just make an init-function and have the constructor call that? You can then call this init again when you want.
Declaring any form of operator new or operator delete in a class hides all other forms of operator new or operator delete that are not redeclared in that class. For this reason any time you provide an overload of at least one form of operator new or operator delete you should provide overloads for all forms of operator new and operator delete.

Also note that your reimplementation of the normal form of operator new does not behave the same as the default operator new. In particular default operator new will never return a null pointer, whereas your overload of operator new might. mallocs behaviour may also not be acceptable in the case of a zero sized allocation.

Finally, what would you expect the syntax Foo->Foo() to do? Stack allocation? We already have a syntax for that. Reinitialisation? We already have a syntax for that (foo = Foo();). Something else?

Σnigma
Hmm, why does placement new call my overloaded Foo new if it exists, but doesn't otherwise call the overloaded global new.


#include <new>#include <stdio.h>void* ::operator new(size_t size) {	printf("\nglobal new");	return malloc(size);}// Dummy class, ignore.class Bar {	int m_y;};class Foo {  public:	Foo() { printf("\nctor"); }	~Foo() { printf("\ndtor"); }	//void* operator new(size_t size, void* place) { printf("\nnew called"); return place; } // <----- (#1) I DON'T ACTUALLY WANT THIS TO BE CALLED.	//void* operator new(size_t size, Bar *bar) { return malloc(size); }	//void* operator new(size_t size) { return malloc(size); }	void operator delete(void* data, Bar *bar) { free(data); }  private:	int m_x;};int main() {	freopen("stdout.txt", "wb", stdout);	printf("test");	void* raw = malloc(sizeof(Foo));	// Allocate the raw memory to be used in the placement new.	Foo* p = new(raw) Foo();	// Attempt the placement new. <----- THIS IS WHERE THE BUG IS.	p->~Foo();	// Placement delete.	free(raw);	// Remove the memory.	return 1;}

If I uncomment #1, it calls my overloaded new.

Outputs:

#1 uncommented. Unfortunately, "new" is called.
testnew calledctordtor


#1 commented. No "new" called.
testctordtor




Maybe I should rephrase the question:

How can I call a constructor (without actually calling an "operator new" function) after I have overloaded new.



Quote:From AP
If you want to reinitialize an object, why not just make an init-function and have the constructor call that? You can then call this init again when you want.

It's just me playing with allocation syntax, so I'd have to write an init-function for every class.
Quote:Original post by Enigma
Finally, what would you expect the syntax Foo->Foo() to do? Stack allocation? We already have a syntax for that. Reinitialisation? We already have a syntax for that (foo = Foo();). Something else?
Σnigma



Um, I suppose it could be called "initialisation" (As opposed to "_re_initialisation).
Basically, it would call function #1 (in the code). You could, of course, pass extra constructor parameters for non-default constructors.

Code:
class Foo() {    Foo() { printf("\nctor"); } // <---- (#1)    ~Foo() { printf("\ndtor"); }};int main() {    Foo* foo = (Foo*)malloc(sizeof(Foo));    printf("\n<0>");    foo->Foo();    printf("\n<1>");    foo->~Foo();    printf("\n<2>");        free(foo);    printf("\n<3>");}

NOTE: Won't compile, this is what I WISH it did.

Output:
<0>ctor<1>dtor<2><3>
Ah, I see. In that case, what would you expect this to do?
class Foo{	public:		Foo()		{			std::cout &lt;&lt; "Foo::Foo\n";		}		~Foo()		{			std::cout &lt;&lt; "Foo::~Foo\n";		}		void Bar()		{			std::cout &lt;&lt; "Foo::Bar\n";		}};class Bar	:	public Foo{	public:		Bar()		{			std::cout &lt;&lt; "Bar::Bar\n";		}		~Bar()		{			std::cout &lt;&lt; "Bar::~Bar\n";		}};int main(){	Foo * foo = static_cast&lt; Foo * &gt;(malloc(sizeof(Foo)));	std::cout &lt;&lt; "&lt;0&gt;\n";	foo-&gt;Bar();	std::cout &lt;&lt; "&lt;1&gt;\n";	foo-&gt;~Bar();	std::cout &lt;&lt; "&lt;2&gt;\n";	free(foo);	std::cout &lt;&lt; "&lt;3&gt;\n";}


As to your earlier question about why your global operator new doesn't get called - It's because you never call global operator new. You replaced global operator new but call placement new (which can't be replaced anyway).

Σnigma
Overloads of operator new only have to provide memory, they don't have to run constructors. The new operator (different from operator new) is responsible for initialisation - and it can't be overloaded:

T* tPtr = new T;//The above line performs the following pseudo codetPtr = operator new(sizeof(T));//either the global or overloaded member versionrun constructor on memory pointed to by tPtr;//you can't control this bit
All new calls causes the constructor to be called. Use the placement new to call your constructor, thats why its there.


#include // defines placement new

class Foo() {
Foo() { printf("\nctor"); } // ");

// foo->Foo(); not the whay to go
new (foo) Foo;
printf("\n");

foo->~Foo();
printf("\n");

free(foo);
printf("\n");
}


If you want to be able to use both placement new and custom new, you need to define both.


class Foo() {
Foo() { printf("\nctor"); } // <
Quote:Original post by Enigma
Ah, I see. In that case, what would you expect this to do?


Fail compilation when you call foo->~Bar() since the class Foo has no member called ~Bar().

But I guess you're trying to say what happens when a class's name is the same as a function of the parent. Shouldn't this just do the default thing of calling the function of the youngest child, since it isn't virtual, which happens to be (in that case) the constructor for Bar.

Maybe if void Foo::Bar() was declared virtual it might be confusing.

So, how about making "ctor" and "dtor" keywords then (still wishing). So you could define a class like:

class Foo() {  public:    ctor() {}    ctor(int x) {}    dtor() {}    dtor(int y) {} // <--- could allow parameters to destructors if this would be a good thing.}int main() {    Foo* foo = (Foo*)malloc(sizeof(Foo));    foo->ctor(1); // <--- placement new.    foo->dtor();  // <--- placement delete.    free(foo);        return 0;}




BTW, your <'s and >'s show as &.l.t.; and &.g.t.; (minus the periods) here. Is that just firefox or has the gd.net tokenizer hiccupped?
Quote:From the AP
All new calls causes the constructor to be called. Use the placement new to call your constructor, thats why its there.

I'm trying to use placement new, compiler won't let me once I overload Foo::operator new().


Nitage:
Do you know how I can explicitly call that "thing" that is responsible for initialisation?


Oh yeah, btw that init-function idea has another problem, classes won't call their parent's constructors unless they also have an init-function and the class calls super->init();


Thanks.



This topic is closed to new replies.

Advertisement