Topic: Is this legal C++?


Author: ajoy@hub.nic.in
Date: 1998/10/13
Raw View
I feel this is syntactically not valid...
The type "T" in the example below is meant to be replaced
by the compiler with "Bar" only when used in the place of
a type specifier ....and not just a  blind replacement of
"T" with "Bar"....

Also note that .... the  constructor "Bar()" would already have gotten
executed once when  the thread of control passed through the stmt
T a;
in foo() { ...}

AJoY

>to think it is in fact not valid.  If it is not valid can someone tell me
>how to do the same thing in a syntacally valid
>way?

>here's the code.

>class Bar
>{
>public:
>  Bar() { }

>  int x;
>};

>template <class T>
>class Foo
>{
>public:
> Foo()
> {
> T a;

> a.T::Bar(); // this works!
> a.T::T(); // C2039: 'T' is not a member of Bar.
> }
>};

>int main(int argc, char **argv)
>{
> Foo<Bar> b;

> return 1;
>}

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1998/10/15
Raw View
Back in AUGUST, someone asked:
> >to think it is in fact not valid.  If it is not valid can someone tell me
> >how to do the same thing in a syntacally valid
> >way?
>
> >here's the code.
>
> >class Bar
> >{
> >public:
> >  Bar() { }
>
> >  int x;
> >};
>
> >template <class T>
> >class Foo
> >{
> >public:
> > Foo()
> > {
> > T a;
>
> > a.T::Bar(); // this works!
> > a.T::T(); // C2039: 'T' is not a member of Bar.
> > }
> >};
>
> >int main(int argc, char **argv)
> >{
> > Foo<Bar> b;
>
> > return 1;
> >}

After another recent response, ajoy@hub.nic.in wrote:
> I feel this is syntactically not valid...
> The type "T" in the example below is meant to be replaced
> by the compiler with "Bar" only when used in the place of
> a type specifier ....and not just a  blind replacement of
> "T" with "Bar"....
>
> Also note that .... the  constructor "Bar()" would already have gotten
> executed once when  the thread of control passed through the stmt
> T a;
> in foo() { ...}
>
> AJoY

Inside template class Foo, variable "a"'s constructor has already
been called, but the code attempts to call it again. We can assume
that the real problem being asked was how to explicitly call a
constructor for a template-parameter class.

Let's rewrite Foo's constructor to do just that:
    template<class T>Foo::Foo() {
        T a;        // Allocates a T on stack, and constructs it
        // Use variable a normally...

        // Now we'll call T's destructor to destroy a.
        // Since a is an auto variable, it will be destroyed again when
        // the scope ends -- so we have to construct it again before then.
        a.~T();     // Explicit call to destructor, but a still on stack

        // At the moment, a is no longer a T object. The only legal
        // accesses to it are ones that treat it as a "chunk of memory,"
        // for instance the address-of operator (&) -- and this assumes
        // that class T doesn't override operator&...

        // Now we're ready to construct a again.
        // We use a syntax known as "placement new".
        new((void*)&a) T;  // Re-construct in place

        // Now we can use re-initialized a normally...

        // Variable a must be "valid" now because it will be automatically
        // destroyed as it goes out of scope...
    }

I believe that this will work as-is on newer compilers. For older
ones, you may have to define "placement new". This function should
do the trick:

    inline void* operator new(size_t, void*addr) { return addr; }

--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Barber <cbarber@fardm4.boston.deshaw.com>
Date: 1998/08/11
Raw View
James Kuyper <kuyper@wizard.net> writes:

> The dangerous but legal way to re-construct
> initialized memory is to explicitly call the destructor, then call
> placement new(). Don't do this unless you know exactly what you are
> doing. In particular, make sure you understand exactly what the
> consequences are with regard to multiple and virtual inheritance. (I'm
> not sure what they are, but I remember that those were issues that
> someone brought up when I first saw this technique discussed).

There is a good discussion of the issues involved in "Guru of the Week"
#23:

    http://www.cntc.com/resources/gotw023.html

--
Christopher Barber ----- Software Engineer ---- D.E.Shaw & Co.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/08/06
Raw View
Pete Becker wrote:
>
> Jason Hunter wrote:
> >
> > As a followup to my own question, I wanted to point out that it is the
> > explicit call to the constructor that I am interested in.
>
> That's not legal.
>
> > For those not clear,
> > this causes the constructor to be called on the "a" object again without
> > the destructor being called.
>
> Or, rather, that's what you would like it to do. <g>
>
> > (Actually this is a paired down example
> > the real storage is allocated from an untyped block of memory and has never
> > been initialized - that is why I need to explicitly call the constructor on
> > it because it has not yet been called.)
>
> No, you don't need to explicitly call the constructor. You have a design
> problem somewhere else. You're asking, in effect, how to put your socks
> on after you've put your shoes on. The right answer is don't get into
> that situation.

That's a very good idea, but the correct question to the shoe question
is "first take off your shoe, then put on your socks". The best answer
to the uninitialized memory question is to avoid it wherever possible.
However, there are legitimate uses for such things, and the correct
answer in such cases is to use placement new() - either directly, or
indirectly through the uninitialized_copy<> or uninitialized_fill<>
functions.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1998/08/07
Raw View
    void* ::operator new(size_t, void*addr) { return addr; }

Since the placement operator new is inline and trivial, you
can construct an object of type T at address t with:
    new(t) T();
and the results call the constructor as "directly" as anyone is
likely to need.

--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Otto Perdeck <otto.perdeck@inter.NL.net>
Date: 1998/08/06
Raw View
You should have gotten 2 errors instead of one. There is no standard way to call the
constructor directly. Destructors can be called directly, constructors not. If you want
to call the constructor explicitly, create some "init" method to do the job.

-Otto Perdeck



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Jon Andri Sigurdarson" <digit@isholf.is>
Date: 1998/08/06
Raw View
If U are using your Bar class in your Foo template class and want to access
the constructor then the:   a.T::Bar()  sentence is not nessesary.  It
really  doesn't do anything what hasn't already been done when U decleare
your variable ( T a; )
So, I don't really get why on earth you wanna make something like:
a.T::T();  work because the constructor is always called when you declare
your variable.
If you wanna call some other functions in the Foo constructor, like I'm
calling Test(),  you have to be sure Test() is always in the class you try
to use with your template class, BUT this is not a good programming habbit
!!!!!!!!!

#include <iostream.h>
class Bar{
public:
 Bar(){cout<<"constructor"<<endl;}
 void Test(){cout<<"test"<<endl;}
 int x;
};
template <class T> class Foo{
public:

(){
  T a;
  //a.T::Bar(); // this doesn't do anything
  a.T::Test(); //
 }
};
int main(int argc, char **argv){
 Foo<Bar> b;
 return 1;
}


I hope this tells you something !

Jon Andri
mailto:digit@isholf.is



Jason Hunter wrote in message <01bdc100$f82d21b0$19011a12@bwing>...
>I have searched all over the C++ spec to see if this code is correct.  I
>think it ought to be, but I haven't been
>able to find a compiler (tried, MSVC, Solais c++, Dec c++, Cxx, g++) who
>will compile it.  In fact, they all give
>approximately the same error.  Since this conservation of errors is pretty
>rare among compilers I am beginning
>to think it is in fact not valid.  If it is not valid can someone tell me
>how to do the same thing in a syntacally valid
>way?
>
>here's the code.
>
>
>class Bar
>{
>public:
>  Bar() { }
>
>  int x;
>};
>
>template <class T>
>class Foo
>{
>public:
> Foo()
> {
> T a;
>
> a.T::Bar(); // this works!
> a.T::T(); // C2039: 'T' is not a member of Bar.
> }
>};
>
>int main(int argc, char **argv)
>{
> Foo<Bar> b;
>
> return 1;
>}



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Jason Hunter" <jthunter@mit.edu>
Date: 1998/08/06
Raw View
>  Foo()
>  {
>   T a;
>
>   a.T::Bar();  // this works!
>   a.T::T();   // C2039: 'T' is not a member of Bar.
>  }
> };
>

As a followup to my own question, I wanted to point out that it is the
explicit call to the constructor that I am interested in.  For those not
clear,
this causes the constructor to be called on the "a" object again without
the destructor being called.  (Actually this is a paired down example
the real storage is allocated from an untyped block of memory and has never

been initialized - that is why I need to explicitly call the constructor on
it
because it has not yet been called.)

 Thanks,

 Jason Hunter
 jthunter[PLEASE REMOVE THIS - SPAMBLOCK]@mit.edu



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1998/08/06
Raw View
Jason Hunter<jthunter@mit.edu> wrote:
>
>struct Bar { Bar() { } int x; };
>
>template <class T>
>struct Foo {
>  Foo() { T a; a.T::T(); } // C2039: 'T' is not a member of Bar.
>};
>Foo<Bar> f;

Here T is Bar, and a.T::T() is equivalent to a.Bar::Bar(),
and sure enough, as your compilers report, Bar::Bar() is not a
member of Bar.  It's a constructor.

>If it is not valid can someone tell me how to do the same thing in
>a syntacally valid way?

I don't know what "the same thing" is, but you might try simply:

  T();

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.org/



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Pete Becker <petebecker@acm.org>
Date: 1998/08/06
Raw View
Jason Hunter wrote:
>
> As a followup to my own question, I wanted to point out that it is the
> explicit call to the constructor that I am interested in.

That's not legal.

> For those not clear,
> this causes the constructor to be called on the "a" object again without
> the destructor being called.

Or, rather, that's what you would like it to do. <g>

> (Actually this is a paired down example
> the real storage is allocated from an untyped block of memory and has never
> been initialized - that is why I need to explicitly call the constructor on
> it because it has not yet been called.)

No, you don't need to explicitly call the constructor. You have a design
problem somewhere else. You're asking, in effect, how to put your socks
on after you've put your shoes on. The right answer is don't get into
that situation.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Pete Becker <petebecker@acm.org>
Date: 1998/08/07
Raw View
The question wasn't about how to convert uninitialized memory to an
object, but how to reinitialize an object that has already been
constructed (although apparently incorrectly). That sounds like a silly
distinction, but it's important: if you need to initialize uninitialized
memory, as you say, there are may ways to do it. If you want to change
an already existing object you are limited to using member functions.
C++ tries its best to make it difficult to invoke constructors on
objects that have already been constructed.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Jason Hunter" <jthunter@mit.edu>
Date: 1998/08/09
Raw View
Pete Becker and James Kuyper

> The question wasn't about how to convert uninitialized memory to an
> object, but how to reinitialize an object that has already been
> constructed (although apparently incorrectly). That sounds like a silly

Actually, you could still use the placement operator new trick even to
reinitialize an already created object.  Just case the object pointer to
void * and then pass it to the new operator.  This is what I have done.
thanks a lot James for the suggestion.  Now that my problem is solved, the
question still remains whether the original snip I sent was legal C++?  Are
there a set of restriction on where and when you can call a constructor
explicitly on an existing object?  I though you could pretty much do it
anywhere.  You can certainly call them from within other constructors and
as I said in the original snippet, if I changed the template function to an
explicit all to the constructor it worked.  Anyone give me a reference to
the spec where it lists the restrictions on this sort of thing?

- jason




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/08/09
Raw View
"Jason Hunter" <jthunter@mit.edu> writes:

>Actually, you could still use the placement operator new trick even to
>reinitialize an already created object.  Just case the object pointer to
>void * and then pass it to the new operator.  This is what I have done.

You don't need an explicit cast, since conversions to void* can
be implicit.

>Are there a set of restriction on where and when you can call a constructor
>explicitly on an existing object?

You are explicitly allowed to destroy an object and create a new
object of the same type in its place. Two examples for a type T:
 void f()
 {
     T* p = new T; // heap object
     p->~T();      // destroy old object
     new (p) T;    // create new object
     delete p;     // destroy new object and return storage

     T q;          // auto object
     q.~T();       // destroy old object
     new (&q) T;   // create new object
     // new object destroyed automatically at function end
 }

You must also be aware that from the time the destructor starts
to run until the time the new constructor has completed, the
object is no longer a T object. In particular, don't modify an
object this way from one of its member functions (or base-class
member functions).

If you create a new object without destroying the old one first,
the results are undefined for any program that depends on side
effects of the destructor. Suppose T locks a resource, unlocked
by the destructor. You need to call the destructor before replacing
the old object.

If you create a new object of a different type in place of the old
one, and if pointers to the object exist, the results are undefined
if you treat the old pointer as anything but a void*. Suppose type
T has a member function f, and we construct a U object in place
of a T object:
 new (p) U;
 p->f();
The last line calls T::f on a U object, which can't be good.
If f is virtual, it the call itself is likely to crash the program.

There are other obvious problems involving size and alignment.
If the new type is bigger or has stricter alignment requirements,
the program is likely to crash.

Section 3.8 "Object lifetime" of the standard has more details.

--
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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/08/10
Raw View
Jason Hunter wrote:
>
> Pete Becker and James Kuyper
>
> > The question wasn't about how to convert uninitialized memory to an
> > object, but how to reinitialize an object that has already been
> > constructed (although apparently incorrectly). That sounds like a silly

Hey! The quoted text is entirely Pete's; I don't deserve any credit for
it. He's right - what I suggested is entirely inappropriate for that
context.

> Actually, you could still use the placement operator new trick even to
> reinitialize an already created object. ...

True.

> ...  Just case the object pointer to
> void * and then pass it to the new operator. ...

Wrong. If the object has actually been constructed, it must be destroyed
before you reconstruct it.

>... This is what I have done.
> thanks a lot James for the suggestion.  Now that my problem is solved, the

No! No! No! Don't credit me with that!. What I said applied only for
unitialized memory. The dangerous but legal way to re-construct
initialized memory is to explicitly call the destructor, then call
placement new(). Don't do this unless you know exactly what you are
doing. In particular, make sure you understand exactly what the
consequences are with regard to multiple and virtual inheritance. (I'm
not sure what they are, but I remember that those were issues that
someone brought up when I first saw this technique discussed).


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/08/10
Raw View
Pete Becker wrote:
>
> The question wasn't about how to convert uninitialized memory to an
> object, but how to reinitialize an object that has already been
> constructed (although apparently incorrectly). That sounds like a

The original message on this thread asked about trying to re-construct
an already constructed object, and what you're saying would be perfectly
correct in that context. However, in a later message

Jason Hunter wrote:
...
> (Actually this is a paired down example
> the real storage is allocated from an untyped block of memory and has never
> been initialized - that is why I need to explicitly call the constructor on
> it because it has not yet been called.)

I was responding to that statement, rather than to the original message.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Jim Cobban" <Jim.Cobban.jcobban@nt.com>
Date: 1998/08/10
Raw View
In article <01bdc328$abd6a140$182510ac@superstition>,
Jason Hunter <jthunter@mit.edu> wrote:
>
>Actually, you could still use the placement operator new trick even to
>reinitialize an already created object.  Just case the object pointer to
        t
>void * and then pass it to the new operator.  This is what I have done.

It is not necessary to cast.  void * is the ultimate base pointer.  You can
assign a pointer to any class object to void * without a cast.

Not that it is a good idea to use this trick just to reinitialize the class.
If you need to reinitialize the class then add a member called reinitialize.
To avoid duplicating code have your constructor call reinitialize.
--
Jim Cobban   |  jcobban@nortel.ca                   |  Phone: (613) 763-8013
Nortel (MCS) |                                      |  FAX:   (613) 763-5199


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Jason Hunter" <jthunter@mit.edu>
Date: 1998/08/06
Raw View
I have searched all over the C++ spec to see if this code is correct.  I
think it ought to be, but I haven't been
able to find a compiler (tried, MSVC, Solais c++, Dec c++, Cxx, g++) who
will compile it.  In fact, they all give
approximately the same error.  Since this conservation of errors is pretty
rare among compilers I am beginning
to think it is in fact not valid.  If it is not valid can someone tell me
how to do the same thing in a syntacally valid
way?

here's the code.


class Bar
{
public:
  Bar() { }

  int x;
};

template <class T>
class Foo
{
public:
 Foo()
 {
  T a;

  a.T::Bar();  // this works!
  a.T::T();   // C2039: 'T' is not a member of Bar.
 }
};

int main(int argc, char **argv)
{
 Foo<Bar> b;

 return 1;
}


Thanks,

Jason Hunter
jthunter[PLEASE REMOVE THIS - SPAMBLOCK]@mit.edu



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: greg@qualcom.qualcomm.com (Greg Noel)
Date: Tue, 1 Dec 1992 23:47:09 GMT
Raw View
This came up as part of an internal discussion and we can't seem to resolve
it here.  Is this code fragment legal C++?

 template <class T>
 class Bar
 {
  friend class T;
  class T *t = 0;
 };

 class Foo : public Bar<Foo>
 {
  friend class Bar<Foo>;
  class Foo *f;
 };

Now, I'm not going to argue that this is good programming practice, but
that's a different topic.  The question on the floor is if this is _legal_,
not whether it's stylisticly reasonable.

Incidentally, G++ accepts this without any problems, and seems to do
what I expect it to do.

Note that followups are directed to comp.lang.c++.

Tks,
--
-- Greg Noel, Unix Guru         greg@qualcomm.com  or  greg@noel.cts.com




Author: greg@qualcom.qualcomm.com (Greg Noel)
Date: Wed, 2 Dec 1992 02:05:07 GMT
Raw View
In article <1992Dec1.234709.5823@qualcomm.com> I wrote:
> class Bar
> {
>  friend class T;
>  class T *t = 0;
     ^^^^ OOPS!
> };

In private e-mail, Steven Parkes has pointed out that this is not permitted
in standard C++.  Since that was not the point of the posting, please ignore
that part.  Sorry!

G++ does seem to permit this as an extension, but I don't have any of the
documentation for G++, so I don't know how it works, except emperically.
If anyone can tell me where to get this documentation, I'd appreciate it.
(If you do, please use e-mail or change the subject thread.  Thanks.)

Followups are again directed to comp.lang.c++.
--
-- Greg Noel, Unix Guru         greg@qualcomm.com  or  greg@noel.cts.com