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! ]
|
|
0
|
|
|
|
Reply
|
SeeWebsiteForEmail (94)
|
7/17/2004 12:03:26 PM |
|
Hi Andrei,
> 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);
> }
....
> 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! ]
|
|
0
|
|
|
|
Reply
|
Vladimir
|
7/19/2004 10:32:48 AM
|
|
On 19 Jul 2004 06:32:48 -0400, Vladimir Prus <ghost@cs.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<TYPELIST_3(B1,B2,B3)>
>::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<TYPELIST_3(B1,B2,B3)>
>::alloc(s);
}
void* operator new(std::size_t s, std::nothrow_t nt) throw() {
return helper< GenScatterHierarchy<TYPELIST_3(B1,B2,B3)>
>::alloc(s,nt);
}
void* operator new(std::size_t s, void* p) {
return helper< GenScatterHierarchy<TYPELIST_3(B1,B2,B3)>
>::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! ]
|
|
0
|
|
|
|
Reply
|
Herb
|
7/19/2004 8:53:44 PM
|
|
Andrei Alexandrescu (See Website for Email) wrote:
> 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<B>::value << endl;
cout << has_operator_new<C>::value << endl;
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<T>::value is
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! ]
|
|
0
|
|
|
|
Reply
|
Marco
|
7/19/2004 8:55:02 PM
|
|
"Herb Sutter" <hsutter@gotw.ca> wrote in message
news:mrtnf01j14qaiv25vgjdvgnf1e42gq1get@4ax.com...
> On 19 Jul 2004 06:32:48 -0400, Vladimir Prus <ghost@cs.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<TYPELIST_3(B1,B2,B3)>
> >::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.
> 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.
> 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);
> }
> };
Cool, just th functions would need to have "static" prepended.
> 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<TYPELIST_3(B1,B2,B3)>
> >::alloc(s);
> }
> void* operator new(std::size_t s, std::nothrow_t nt) throw() {
> return helper< GenScatterHierarchy<TYPELIST_3(B1,B2,B3)>
> >::alloc(s,nt);
> }
> void* operator new(std::size_t s, void* p) {
> return helper< GenScatterHierarchy<TYPELIST_3(B1,B2,B3)>
> >::alloc(s,p);
> }
> };
A typedef for helper<...> would help so you can later solve ambiguities.
> 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! ]
|
|
0
|
|
|
|
Reply
|
Andrei
|
7/21/2004 8:17:00 PM
|
|
> 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! ]
|
|
0
|
|
|
|
Reply
|
drac
|
7/22/2004 10:49:35 PM
|
|
Cristian Adam wrote:
> 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! ]
|
|
0
|
|
|
|
Reply
|
Marco
|
7/23/2004 2:26:06 PM
|
|
|
6 Replies
88 Views
(page loaded in 0.18 seconds)
Similiar Articles: Overloading operators new and delete - comp.lang.c++.moderated ...Dear experts, Please, consider the following example code: void * CLASS_A::operator new( size_t size ){ return Stack::pop(); } void CLASS_A::ope... [ace-users] No overloaded ostream operator << for ACE_Time_Value ...... streamtheworld.com streamtheworld.com =A0 StreamTheWorld launches its new ... The source demonstrates the use of some of the overloaded operator<< functions shown above ... Non-member operator overloading, linker complains - comp.lang.c++ ...... pragmas or linker ... allocate memory from Windows, they call the operator new ... ... C++ Tutorials - Lesson 24: Operator Overloading Operator overloading is the ability to ... STL allocators, global new/delete using the heap and shared memory ...Overloading operators new and delete - comp.lang.c++.moderated ... Overloading operators new and delete - comp.lang.c++.moderated ... STL allocators, global new/delete ... between-and operator - comp.soft-sys.sasOverloading operators new and delete - comp.lang.c++.moderated ... Dear experts, Please, consider the following example code: void * CLASS_A::operator new( size_t size ... tdelete() example? - comp.lang.cOverloading operators new and delete - comp.lang.c++.moderated ... Dear experts, Please, consider the following example code: void * CLASS_A::operator new( size_t size ... Newbie cache alignment question - comp.lang.c++.moderated ...This wil obviously waste a lot of memory for smaller items so you could do it otherwise by overloading the class operator new and delete to do this for you. left-hand operand of comma has no effect - comp.lang.c++ ...Hi all, I like to implement a new syntax in C++ ... the meaning is a+b, then why don't you simply overload ... > > inline myClass operator (myClass &left, myClass &right ... comp.lang.c++.moderated - page 74operator new[] question 8 59 (12/4/2003 12:50:45 AM) hi, i am having problems ... function overloading 6 72 (12/2/2003 9:36:46 PM) Hi all, can anybody explain to me why ... How to simulate variadic templates? - comp.lang.c++.moderated ...Therefore I create the object using a "New<>" template. template ... inplace (from temporaries) a boost::tuple<> can pe done too (using operator overloading ... Overloading New in C++ - Bear Products International Home PageSince at least 1993 C++ has defined a way to overload the new operator for a given class. By providing an overloaded verion of new for a class (e.g., my_class above), there ... Operator New and Operator Delete in C++ - Cprogramming.comHow and why to overload operator new (and operator delete) in C++ 7/30/2012 6:49:29 AM
|