C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

overloading operator new

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Andrei Alexandrescu (See
Guest





PostPosted: Sat Jul 17, 2004 12:03 pm    Post subject: overloading operator new Reply with quote



While reading items 22 and 23 in Herb Sutter's Exceptional C++ (about new
overloading) I came to an interesting question.

For a derived class, is it possible to call the base version of new if the
base happened to overload it, or else call the global version?

IOW: I design class D derived from B. I add some overload of new:

class D : public B {
public:
void* operator new(size_t, Gizmo&);
};

Now according to Herb's guideline, D's author should provide all of other
legit overloads. But the thing is, D's writer does not to modify D whenever
B's implementer chose to define (or not) their own overloads. If B overloads
new for sure, cool:

class D : public B {
public:
void* operator new(size_t, Gizmo&);
using B::operator new;
};

If B did not overload new, cool again:

class D : public B {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return ::operator new(s);
}
... etc. etc. ...
};

But how can D's author unify the two such that D does the right thing
whether or not B overloaded new?


Andrei



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vladimir Prus
Guest





PostPosted: Mon Jul 19, 2004 10:32 am    Post subject: Re: overloading operator new Reply with quote



Hi Andrei,

Quote:
class D : public B {
public:
void* operator new(size_t, Gizmo&);
using B::operator new;
};

If B did not overload new, cool again:

class D : public B {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return ::operator new(s);
}

....

Quote:
But how can D's author unify the two such that D does the right thing
whether or not B overloaded new?

I think a possible approach was suggested by Peter Dimov on the Boost
mailing list. The original post is
http://article.gmane.org/gmane.comp.lib.boost.devel/92076

and it can be applied to this case like this:

template<class T> struct helper: public T
{
static void * alloc(size_t size)
{
return operator new(size);
}
};

class D : public B {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return helper<B>::alloc(s);
}

Complete example at http://zigzag.cs.msu.su/~ghost/new.cpp appears to do
what you want.

- Volodya


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Herb Sutter
Guest





PostPosted: Mon Jul 19, 2004 8:53 pm    Post subject: Re: overloading operator new Reply with quote



On 19 Jul 2004 06:32:48 -0400, Vladimir Prus <ghost (AT) cs (DOT) msu.su> wrote:
Quote:
template<class T> struct helper: public T
{
static void * alloc(size_t size)
{
return operator new(size);
}
};

class D : public B {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return helper<B>::alloc(s);
}

Complete example at http://zigzag.cs.msu.su/~ghost/new.cpp appears to do
what you want.

Cool. What if there are multiple base classes -- will this work?

class D : public B1, public B2, public B3 {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return helper< GenScatterHierarchy
Quote:
::alloc(s);
}

};

Andrei?


Also, note that there are three forms of op new that you want, not just
this one. So what you really need is (sketching):

template<class T> struct helper : public T {
void* alloc(std::size_t s) {
return operator new(s);
}
void* alloc(std::size_t s, std::nothrow_t nt) throw() {
return operator new(s, nt);
}
void* alloc(std::size_t s, void* p) {
return operator new(s, p);
}
};

And then in each class you have to write:

class D : public B1, public B2, public B3 {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return helper< GenScatterHierarchy
Quote:
::alloc(s);
}

void* operator new(std::size_t s, std::nothrow_t nt) throw() {
return helper< GenScatterHierarchy
Quote:
::alloc(s,nt);
}

void* operator new(std::size_t s, void* p) {
return helper< GenScatterHierarchy
Quote:
::alloc(s,p);
}

};


Could you simplify this further by the adjustment:

template<class T> struct helper_1 : public GenScatterHierarchy<T> {
void* alloc(std::size_t s) {
return operator new(s);
}
void* alloc(std::size_t s, std::nothrow_t nt) throw() {
return operator new(s, nt);
}
void* alloc(std::size_t s, void* p) {
return operator new(s, p);
}
};
// (I think this will give you errors if more than one of the
// bases defined op new, but that's probably a feature.)

template<class T> struct helper_2 : public helper_1<T> {
void* operator new(size_t s) {
return helper_1<T>::alloc(s);
}
void* operator new(std::size_t s, std::nothrow_t nt) throw() {
return helper_1<T>::alloc(s,nt);
}
void* operator new(std::size_t s, void* p) {
return helper_1<T>::alloc(s,p);
}
};

Then you can just write:

class D : helper_2<TYPELIST_3(B1,B2,B3)> {
public:
void* operator new(size_t, Gizmo&);
using helper_2<TYPELIST_3(B1,B2,B3)>::operator new;
};

That's just a sketch. Would such an approach work?

Herb

---
Herb Sutter (www.gotw.ca)

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Visual C++ architect, Microsoft (www.gotw.ca/microsoft)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Marco Manfredini
Guest





PostPosted: Mon Jul 19, 2004 8:55 pm    Post subject: Re: overloading operator new Reply with quote

Andrei Alexandrescu (See Website for Email) wrote:

Quote:
But how can D's author unify the two such that D does the right thing
whether or not B overloaded new?

I think a solution along the SFINAE principle could help. Here is a
quick hack for a "has_operator_new<T>" predicate, which tells me if
there is an operator new in T defined:

//====================== BEGIN =========================================
// compile-time "has_operator_new" predicate. Not checked for quirks.
#include <stdlib.h>
typedef char (&no_tag)[0];
typedef char (&yes_tag)[1];

template<void *(*fn)(size_t)>
struct has_new_helper
{
typedef yes_tag Result;
};

// has_new_helper returns a "yes_tag" if there is a possible
// substitution for T::operator new, which matches the signature
// in has_new_helper<...>.
template<class T>
typename has_new_helper<T::operator new>::Result
has_new_fn(T*);

// default case
// (with an undesireable conversion to avoid ambigous conversion)
no_tag
has_new_fn(void*);

template<class T>
struct has_operator_new
{
enum
{
value = sizeof(has_new_fn((T*)0)) == sizeof(yes_tag)
};
};

#include <iostream>
using namespace std;

class B
{
public:
static void *operator new(size_t sz);
};
class C
{
};

int main()
{
cout << has_operator_new cout << has_operator_new return 0;
}
//========================== END ==============================

This should print
1
0
when compiled with decent compiler. I've checked it with gcc-3.4.1 and
msvc-7.1 (gcc-3.3.4 doesn't work!). Since has_operator_new a compile time constant, it should be quite easy now to implement the
requested functionality.

Greetings
Marco










[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Andrei Alexandrescu (See
Guest





PostPosted: Wed Jul 21, 2004 8:17 pm    Post subject: Re: overloading operator new Reply with quote

"Herb Sutter" <hsutter (AT) gotw (DOT) ca> wrote

Quote:
On 19 Jul 2004 06:32:48 -0400, Vladimir Prus <ghost (AT) cs (DOT) msu.su> wrote:
template<class T> struct helper: public T
{
static void * alloc(size_t size)
{
return operator new(size);
}
};

class D : public B {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return helper<B>::alloc(s);
}

Complete example at http://zigzag.cs.msu.su/~ghost/new.cpp appears to do
what you want.

Cool. What if there are multiple base classes -- will this work?

class D : public B1, public B2, public B3 {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return helper< GenScatterHierarchy ::alloc(s);
}
};

Cool. That should work, except when more than one base defines overloads,
case in which there's an ambiguity. By controlling the typelist you can
easily select which overload should be in effect.

I like the solution above a tad better than the one using the sizeof
operator to find the presence of the overload.

Quote:
Also, note that there are three forms of op new that you want, not just
this one.

You know what. It just occured to me that each class-specific operator new
that could throw should also be accompanied by a variant that takes
std::nothrow_t as its last argument. This is a nice touch I'd think.

Quote:
So what you really need is (sketching):

template void* alloc(std::size_t s) {
return operator new(s);
}
void* alloc(std::size_t s, std::nothrow_t nt) throw() {
return operator new(s, nt);
}
void* alloc(std::size_t s, void* p) {
return operator new(s, p);
}
};

Cool, just th functions would need to have "static" prepended.

Quote:
And then in each class you have to write:

class D : public B1, public B2, public B3 {
public:
void* operator new(size_t, Gizmo&);
void* operator new(size_t s) {
return helper< GenScatterHierarchy ::alloc(s);
}
void* operator new(std::size_t s, std::nothrow_t nt) throw() {
return helper< GenScatterHierarchy ::alloc(s,nt);
}
void* operator new(std::size_t s, void* p) {
return helper< GenScatterHierarchy ::alloc(s,p);
}
};

A typedef for helper<...> would help so you can later solve ambiguities.

Quote:
Could you simplify this further by the adjustment:

template<class T> struct helper_1 : public GenScatterHierarchy<T> {
void* alloc(std::size_t s) {
return operator new(s);
}
void* alloc(std::size_t s, std::nothrow_t nt) throw() {
return operator new(s, nt);
}
void* alloc(std::size_t s, void* p) {
return operator new(s, p);
}
};
// (I think this will give you errors if more than one of the
// bases defined op new, but that's probably a feature.)

template<class T> struct helper_2 : public helper_1<T> {
void* operator new(size_t s) {
return helper_1<T>::alloc(s);
}
void* operator new(std::size_t s, std::nothrow_t nt) throw() {
return helper_1<T>::alloc(s,nt);
}
void* operator new(std::size_t s, void* p) {
return helper_1<T>::alloc(s,p);
}
};

Then you can just write:

class D : helper_2<TYPELIST_3(B1,B2,B3)> {
public:
void* operator new(size_t, Gizmo&);
using helper_2<TYPELIST_3(B1,B2,B3)>::operator new;
};

That's just a sketch. Would such an approach work?

Aha, so the idea is to define helper_2 as a class that *definitely*
overloads operator new, which reduces the problem to one of choosing the
appropriate using overloads.

FWIW, the inheritance above might not be of optimal size. Compilers don't
apply EBO very aggressively to multiple inheritance.

I am increasingly thinking that a "alloc_helper" class (such as the ones
sketched above) should be in the standard to allow proper overloading of new
for classes.


Andrei



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Cristian Adam
Guest





PostPosted: Thu Jul 22, 2004 10:49 pm    Post subject: Re: overloading operator new Reply with quote

Quote:
when compiled with decent compiler. I've checked it with gcc-3.4.1 and
msvc-7.1 (gcc-3.3.4 doesn't work!). Since has_operator_new<T>::value is
a compile time constant, it should be quite easy now to implement the
requested functionality.

Are you sure it's working on msvc-7.1? I've tested the program and it chokes
at line typedef char (&no_tag)[0] with these errors:

error C2466: cannot allocate an array of constant size 0
error C2265: '<Unknown>' : reference to a zero-sized array is illegal

Cheers,
Cristi.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Marco Manfredini
Guest





PostPosted: Fri Jul 23, 2004 2:26 pm    Post subject: Re: overloading operator new Reply with quote

Cristian Adam wrote:

Quote:
Are you sure it's working on msvc-7.1? I've tested the program and it
chokes at line typedef char (&no_tag)[0] with these errors:

error C2466: cannot allocate an array of constant size 0
error C2265: '<Unknown>' : reference to a zero-sized array is illegal


Ooops. I've checked it while I was writing this and forgot to sync back
the gcc-ism that slipped in:

typedef char (&no_tag)[1];
typedef char (&yes_tag)[2];

Cheers ;-)

Marco


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.