Topic: Q: T::operator new (size_t) implicitely defined for any T ?


Author: "Markus Mauhart" <Markus.Mauhart@chello.at>
Date: 2000/11/21
Raw View
"Stephen Clamage" <stephen.clamage@sun.com> wrote in message news:ncfp0t4898c3f9lf89j2f63qgbvi6oang1@4ax.com...
> On Sun,  5 Nov 2000 22:34:15 CST, "Markus Mauhart"
> <Markus.Mauhart@chello.at> wrote:
> >I want to write template code that works regardless
> >wether the types supplied as template arguments have class specific
> >new/delete or not.
> >
> >stdc++ allows ..
> >  template<class T> void f ()
> >    {void*a=new char[sizeof(T)]; T* t=new(a)T(); t->T::~T(); delete[]a;}
> >
> >but it does not allow ..
> >  template<class T> void f ()
> >    {void*a=T::operator new(sizeof(T)); T* t=new(a)T(); delete t;}

> (1) You seem to want to be able to bypass the normal operation of a
> new-expression, (2) yet use the class-specific operator new if there is
> one. (3) It doesn't seem to me that this is a very common requirement.

Yes for 1,2,3.
ad 1: not for every T, but for all T derived from my BASE.
  I have to do something() immediately before BASE::BASE():
  Allthough the program and semantic is not broken if there
  comes T::op new() inbetween something() and BASE(), with
  multiple threads its better to have "T::op new();some();BASE();".
ad 2: I must use the class specific new function "T::operator new(..)",
  cause other parties will do the delete (this is given code), while
  I am responsible for the object creation.
  And others are responsible for definition and implemenatation of T.
ad 3: since 2'91 its the first time that I needed it.

> There are some things that are easy to express in C++, such as my
> example, and some that are not, such as your example. Making your
> example easy to express seems to me to require quite a bit of extra
> complication of the language, for very little gain.

No, why is "T::operator new()" more complicated than "t->T::~T()" ?
IMHO the language is more complicated when 'T::op new/delete' have
an exceptional status compared with all other special member
functions I am aware.

> You claim it was an oversight not to provide predefined opeator new
> and delete for every class.

Not really; I asked for the reasons why T::operator new/delete are
not treated like the other special member functions for which
it is possible to call them explicitely in c++ template code
(T::~T , T::operator=).
For now I guess that it's an oversight, but I know there may be
some strong reasons; recently in this group there was a discussion
about the long and stony way new features have to go, and someone
has pointed out that one great problem is to check them for unwanted
implications and interferences.
So if this exception for new/delete (which makes the language more
complicated) was no oversight I thought that someone had found out
the unwanted implications and interferences I am not aware.

> Perhaps so, but I think if it had been proposed (and perhaps it
> was proposed), it would not have been adopted.

IMHO an proposed exceptional behaviour for T::operator would not
have been adopted by the commitee without good reasons.
But the question remains whether the current exceptional treatment
is based on someone's proposal or on oversight.

But I may be wrong and you may be right, so let's return to
the production of code.


Markus.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: 2000/11/21
Raw View
In article <Q0pS5.228832$Le2.12259775@news.chello.at>, Markus Mauhart
<Markus.Mauhart@chello.at> writes
>So if this exception for new/delete (which makes the language more
>complicated) was no oversight I thought that someone had found out
>the unwanted implications and interferences I am not aware.

So what call should be generated when the global delete has been
overridden (remember that with separate compilation the compiler may not
be able to see that).

My point is that generating any of the big four requires no more
knowledge than the class definition, generating operator new, operator
new[], operator delete and operator delete[] requires knowledge of user
definable items that are external to the class definition.

>

Francis Glassborow      Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Stephen Clamage <stephen.clamage@sun.com>
Date: 2000/11/20
Raw View
On Sun,  5 Nov 2000 22:34:15 CST, "Markus Mauhart"
<Markus.Mauhart@chello.at> wrote:

>
>"Steve Clamage" <stephen.clamage@sun.com> wrote in message news:3A04A387.77998BBA@sun.com...
>> Markus Mauhart wrote:
>> >
>> > Q2. If this is correct for stdc++, does anyone know some reasons
>> >   that lead to the decision not to require implicitely declared
>> >   versions of the 2 special member functions new/delete ?
>>
>> The predefined member functions implement operations that are
>> predefined for all types: construction, destruction, copying.
>> These operations are necessarily different for every type.
>>
>> The language also provides predefined dynamic memory allocation.
>> The allocation functionality is defined so that is the same
>> for every type. Thus, there is a set of global allocators, which
>> are adequate for ordinary purposes.
>
>I dont really understand this, e.g. the terms 'different for any type'
>and 'the same for any type': construction, destruction & copy are
>are the same for all 'primitive' types (PODs ?), while memory
>allocation at least respects each types allignment.

Oh, please. First of all, details of initialization are not
necessarily the same for primitive types. The default initialization
for scalar types is the value zero, but the representation of the zero
value for different scalar types need not be the same. The
representation of non-zero values for numeric types is in general
different for every numeric type. (Some types might share a
representation as an implementation detail.)

But surely this discussion is about class types.

The fact of construction and destruction for ANY type is predefined
(in general, different for every type, but possibly the same, if only
by accident, for some sets of different types).

There is exactly one pre-defined mechanism for allocation of dynamic
memory for all types, built-in or user-defined: some version of
operator new. It is required to return (if possible) at least the
requested amount of memory, suitably aligned for any object of the
requested size.

>
>Not at all: I want to write template code that works regardless
>wether the types supplied as template arguments have class specific
>new/delete or not.
>
>stdc++ allows ..
>  template<class T> void f ()
>    {void*a=new char[sizeof(T)]; T* t=new(a)T(); t->T::~T(); delete[]a;}
>
>but it does not allow ..
>  template<class T> void f ()
>    {void*a=T::operator new(sizeof(T)); T* t=new(a)T(); delete t;}

But you can write
 template<class T> void f()
 {T* t = new T; delete t;}
which has the same effect as what you would like for your second
example: the code uses the class-specific operator new if there is one
and the global operator new otherwise, then calls default constructor.

You seem to want to be able to bypass the normal operation of a
new-expression, yet use the class-specific operator new if there is
one. It doesn't seem to me that this is a very common requirement.

There are some things that are easy to express in C++, such as my
example, and some that are not, such as your example. Making your
example easy to express seems to me to require quite a bit of extra
complication of the language, for very little gain.

You claim it was an oversight not to provide predefined opeator new
and delete for every class. Perhaps so, but I think if it had been
proposed (and perhaps it was proposed), it would not have been
adopted.

---
Steve Clamage, stephen.clamage@sun.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: "Markus Mauhart" <Markus.Mauhart@chello.at>
Date: 2000/11/08
Raw View
"Ralph D. Ungermann" <ungermann@flexis.de> wrote in message news:3A05D261.A4F331DA@flexis.de...
> Markus Mauhart wrote:
> >
> > Or is there another way to call any type A's
> > 'operator new'-function corresponding to the expressions
> > "new A()" and "delete (A*)p" ?
>
>
> Yes, there are corresponding operators:
>
>    A * pa = new A; // calls A::op new() or ::op new(), then A()
> and
>    delete pa;      // calls ~A(), then A::op delete() or ::op delete()
>
>
> No need to reinvent these operators!
>
> Isn't C++ nice?
>
>
> If you're still confused, try the following:

Hi Ralph,
probably you were in a hurry and didnt read my question
carefully enough, otherwise you would have understood it.
If you take a look at it you will see that I didnt ask
how to "calls A::op new() or ::op new(), then A()",
instead I asked for the "calls A::op new() or ::op new()"
allone, i.e. how to name the 'operator new function' that
is called when the compiler resolves the 'new expression'
"new A" for an arbitrary type A.



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Stephen Clamage <stephen.clamage@sun.com>
Date: Sat, 4 Nov 2000 04:32:11 GMT
Raw View
On Mon, 30 Oct 2000 19:10:17 GMT, "Markus Mauhart"
<Markus.Mauhart@chello.at> wrote:

>Given ..
>  struct A {A() ;void* operator new (size_t) ;};
>
>the following is valid and should work as expected ..
>  A* newA ()
>    {void* tmp = A::operator new (sizeof(A));
>     important()                ;
>     return ::new (tmp) A()     ;
>    }
>  void delA(A*x) {delete x;}
>
>Now I wanted newA()/delA() to work without user defined
>A::operator new(..), but with my compiler there was no
>predefined A::operator new(..).
>Is this implementation correct ?
>Or is there another way to call any type A's
>'operator new'-function corresponding to the expressions
>"new A()" and "delete (A*)p" ?

I don't understand your question, but let me try a simple explanation.

When you write
 A* p = new A;
the compiler looks first for an operator new declared in or inherited
by class A, accepting a single size_t argument. If there is one, it is
used. If not, the predeclared global operator new is used. Similar
considerations apply to delete operations.

If that doesn't answer your question, try asking again.

---
Steve Clamage, stephen.clamage@sun.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Markus Mauhart" <Markus.Mauhart@chello.at>
Date: 2000/11/04
Raw View
"Stephen Clamage" <stephen.clamage@sun.com> wrote in message news:3m270tcqmoo3q8sf43ojljju5i5cr349v5@4ax.com...
> On Mon, 30 Oct 2000 19:10:17 GMT, "Markus Mauhart"
> <Markus.Mauhart@chello.at> wrote:
>
> >Given ..
> >  struct A {A() ;void* operator new (size_t) ;};
> >
> >the following is valid and should work as expected ..
> >  A* newA ()
> >    {void* tmp = A::operator new (sizeof(A));
> >     important()                ;
> >     return ::new (tmp) A()     ;
> >    }
> >  void delA(A*x) {delete x;}
> >
> >Now I wanted newA()/delA() to work without user defined
> >A::operator new(..), but with my compiler there was no
> >predefined A::operator new(..).
> >Is this implementation correct ?
> >Or is there another way to call any type A's
> >'operator new'-function corresponding to the expressions
> >"new A()" and "delete (A*)p" ?
>
> I don't understand your question, but let me try a simple explanation.
>
> When you write
> A* p = new A;
> the compiler looks first for an operator new declared in or inherited
> by class A, accepting a single size_t argument. If there is one, it is
> used. If not, the predeclared global operator new is used. Similar
> considerations apply to delete operations.

yes

> If that doesn't answer your question, try asking again.

Ok, try again.

1st there comes an "outline" of the situation the lead me to
the question. It is IMHO much too long, so feel free to goto ..
2nd "Conclusion" with two questions.

1. outline :
Given some classes A, (i.e. different A's).

In the module there will be objects of type P<A>:A {...}.
The template class P<T> is from another party,
it uses A::A() to construct its subobjects.
The objects will be destructed through P<A> member
functions, destruction done through "delete this".

I've to create the P<A>'s: e.g. return new P<A>().

Now a change in policy:
Each A in its ctor needs access to some
non-const global data.

Implementation:
-> A common baseclass for all A's:
struct Abase {Abase(){useGlobalData();unlock();}}
P<A>* createA {lock(); setGlobalData() ;return new P<A>;}

Note: is is not pssbl to move the unlock() from Abase()
to createA(), cause each A has additional other base
classes and its own ctor, which might need access to
a different version of global data.

This works as desired.

Last change to decrease thread-blocking during lock()-time:
P<A>* createA ()
{void*a="new memory for A" ;lock(); setGlobalData() ;return new(a) P<A>;}

This is the problem:
How to write code for "new memory for A" so that
"A* p=createA() ;delete p;" will work the same way as
"A* p=new A() ;delete p;" , without placing constraints
on each type A's 'operator new()' + 'operator delete()'
pair.
The 1st solution ..
"new memory for A" {void* p = ::operator new(sizeof(A)) ;}
... has the constraint that no A may have its own new/delete
strategy.
The 2nd solution I'm currently using ..
"new memory for A" {void* p = A::operator new(sizeof(A)) ;}
... with my compiler has the constraint that I have to
introduce a dummy Abase::operator new/delete pair,
implemented through calling the global new/delete functions.

I was surprised that my compiler forces me to define
Abase::operator new(), cause I had assumed that a implicitely
declared T::operator new() is available for each T the same way
as with the other implicitely declared special member functions,
e.g.
//stdc++, 12.1:
  struct A { }; // implicitly-declared A::operator=
  struct B : A {
  B& operator=(const B &);
  };
  B& B::operator=(const B& s) {
  this->A::operator=(s); // well-formed
  return *this;
  }

2. Conclusion:
In stdc++ for each type there are many implicitely declared
special member functions (if not explicitelt declared),
e.g. int::operator= and int::~int.
To my surprise my compiler provides no implicitely declared
special member functions operator new or operator delete,
e.g. int::operator new(size_t).
  Hence my questions are:
Q1. Is this compiler behaviour correct ?
Q2. If this is correct for stdc++, does anyone know some reasons
  that lead to the decision not to require implicitely declared
  versions of the 2 special member functions new/delete ?


Thanks for any hints,
Markus.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/11/05
Raw View
Markus Mauhart wrote:
>
> 2. Conclusion:
> In stdc++ for each type there are many implicitely declared
> special member functions (if not explicitelt declared),
> e.g. int::operator= and int::~int.
> To my surprise my compiler provides no implicitely declared
> special member functions operator new or operator delete,
> e.g. int::operator new(size_t).
>   Hence my questions are:
> Q1. Is this compiler behaviour correct ?

Yes. That has always been the rule in C++, and is what the standard says.

> Q2. If this is correct for stdc++, does anyone know some reasons
>   that lead to the decision not to require implicitely declared
>   versions of the 2 special member functions new/delete ?

The predefined member functions implement operations that are
predefined for all types: construction, destruction, copying.
These operations are necessarily different for every type.

The language also provides predefined dynamic memory allocation.
The allocation functionality is defined so that is the same
for every type. Thus, there is a set of global allocators, which
are adequate for ordinary purposes.

If you want class-specific operator new and delete, you write them.
Otherwise, the global versions are used.

--
Steve Clamage, stephen.clamage@sun.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: "Markus Mauhart" <Markus.Mauhart@chello.at>
Date: 2000/11/05
Raw View
"Steve Clamage" <stephen.clamage@sun.com> wrote in message news:3A04A387.77998BBA@sun.com...
> Markus Mauhart wrote:
> >
> > 2. Conclusion:
> > In stdc++ for each type there are many implicitely declared
> > special member functions (if not explicitelt declared),
> > e.g. int::operator= and int::~int.
> > To my surprise my compiler provides no implicitely declared
> > special member functions operator new or operator delete,
> > e.g. int::operator new(size_t).
> >   Hence my questions are:
> > Q1. Is this compiler behaviour correct ?
>
> Yes. That has always been the rule in C++, and is what the standard says.

Ok, I was not sure about the standard cause there are so many pages
to browse.
But regarding "That has always been the rule in C++" .. in the old
days it had been the rule that there is no int::operator= nor
int::~int; this has been introduced (IMHO) to allow template
code to work for any type, and this is now exactly my problem
with T::operator new.

> > Q2. If this is correct for stdc++, does anyone know some reasons
> >   that lead to the decision not to require implicitely declared
> >   versions of the 2 special member functions new/delete ?
>
> The predefined member functions implement operations that are
> predefined for all types: construction, destruction, copying.
> These operations are necessarily different for every type.
>
> The language also provides predefined dynamic memory allocation.
> The allocation functionality is defined so that is the same
> for every type. Thus, there is a set of global allocators, which
> are adequate for ordinary purposes.

I dont really understand this, e.g. the terms 'different for any type'
and 'the same for any type': construction, destruction & copy are
are the same for all 'primitive' types (PODs ?), while memory
allocation at least respects each types allignment.
IMHO this was not the original argumentation, for now I think new/delete
simply have been forgotten and if I want it I have to implement it
and write a proposal ;-) No, I can live without it, but I'm surprised
about it.

> If you want class-specific operator new and delete, you write them.

Not at all: I want to write template code that works regardless
wether the types supplied as template arguments have class specific
new/delete or not.

stdc++ allows ..
  template<class T> void f ()
    {void*a=new char[sizeof(T)]; T* t=new(a)T(); t->T::~T(); delete[]a;}

but it does not allow ..
  template<class T> void f ()
    {void*a=T::operator new(sizeof(T)); T* t=new(a)T(); delete t;}


Markus.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: "Ralph D. Ungermann" <ungermann@flexis.de>
Date: 2000/11/06
Raw View
Markus Mauhart wrote:
>
> I would be happy if some new/delete expert here can give me
> the answer to the following problem.
>
> Given ..
>   struct A {A() ;void* operator new (size_t) ;};
>
> the following is valid and should work as expected ..
>   A* newA ()
>     {void* tmp = A::operator new (sizeof(A));
>      important()                ;
>      return ::new (tmp) A()     ;
>     }
>   void delA(A*x) {delete x;}
>
> Now I wanted newA()/delA() to work without user defined
> A::operator new(..), but with my compiler there was no
> predefined A::operator new(..).
> Is this implementation correct ?
> Or is there another way to call any type A's
> 'operator new'-function corresponding to the expressions
> "new A()" and "delete (A*)p" ?


Yes, there are corresponding operators:

   A * pa = new A; // calls A::op new() or ::op new(), then A()
and
   delete pa;      // calls ~A(), then A::op delete() or ::op delete()


No need to reinvent these operators!

Isn't C++ nice?


If you're still confused, try the following:


struct A
{
  A() { std::cerr << " A() called " ; }

  void * operator new(size_t s)
  {
    std::cerr << " A::new(" << s << ") at " ; }
    void * p = malloc(s) ;
    std::cerr << p ;

    important() ; // whatever this is good for

    return p ;
  }
} ;


Get it?


Regards,
Ralph

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: "Markus Mauhart" <Markus.Mauhart@chello.at>
Date: Mon, 30 Oct 2000 19:10:17 GMT
Raw View
I would be happy if some new/delete expert here can give me
the answer to the following problem.

Given ..
  struct A {A() ;void* operator new (size_t) ;};

the following is valid and should work as expected ..
  A* newA ()
    {void* tmp = A::operator new (sizeof(A));
     important()                ;
     return ::new (tmp) A()     ;
    }
  void delA(A*x) {delete x;}

Now I wanted newA()/delA() to work without user defined
A::operator new(..), but with my compiler there was no
predefined A::operator new(..).
Is this implementation correct ?
Or is there another way to call any type A's
'operator new'-function corresponding to the expressions
"new A()" and "delete (A*)p" ?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]