This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: Not Const Temporaries
- To: Philippe Cizaire <pci at silicomp dot com>
- Subject: Re: Not Const Temporaries
- From: Ingo Krabbe <ikrabbe at earthling dot net>
- Date: Sat, 5 May 2001 10:01:56 +0200 (CEST)
- cc: <gcc-help at gcc dot gnu dot org>
- Reply-To: Ingo Krabbe <i dot krabbe at dokom dot net>
On Wed, 2 May 2001, Philippe Cizaire wrote:
>
> Any hints/clue to make it work ?
>
> // file test.cc
> #include <stdio.h>
>
> class TKeeped;
> class TKeeper
> {
> TKeeped &keeped;
>
> void Init(void);
> void Reset(void);
> public:
> TKeeped &Keeped(void) { return keeped; }
>
> TKeeper(TKeeped &_keeped) : keeped(_keeped) { Init(); }
> ~TKeeper(void) { Reset(); }
>
> TKeeper(TKeeper &keeper) : keeped(keeper.Keeped()) { Init(); }
>
> private:
> static int created;
> public:
> static int Created(void) { return created; }
> };
>
> class TKeeped
> {
> int count;
> public:
> TKeeped(void);
> ~TKeeped(void);
>
> static TKeeper New(void);
> private:
> friend TKeeper;
> void KeeperAdd(void);
> void KeeperRemove(void);
> };
>
> int TKeeper::created = 0;
> void TKeeper::Init(void)
> {
> ++created;
> printf("TKeeper[%08X](TKeeped[%08X])::Init (%d)\n",
> this, &Keeped(), created);
> Keeped().KeeperAdd();
> }
>
> void TKeeper::Reset(void)
> {
> printf("TKeeper[%08X](TKeeped[%08X])::Reset\n", this, &Keeped());
> Keeped().KeeperRemove();
> }
>
> TKeeped::TKeeped(void) :
> count(0)
> {
> printf("TKeeped[%08X]\n", this);
> }
>
> TKeeped::~TKeeped(void)
> {
> printf("~TKeeped[%08X]\n", this);
> }
>
> void TKeeped::KeeperAdd(void)
> {
> printf("TKeeped[%08X](%d)::++\n", this, count);
> ++count;
> }
>
> void TKeeped::KeeperRemove(void)
> {
> printf("TKeeped[%08X](%d)::--\n", this, count);
> if(--count) return;
> delete this;
> }
>
> TKeeper TKeeped::New(void)
> {
> return TKeeper(* new TKeeped);
> }
>
> int main(void)
> {
> {
> printf("before\n");
> TKeeper keeper(TKeeped::New());
> printf("after\n");
> }
> printf("out of scope\n");
> printf("total keeper created : %d\n", TKeeper::Created());
> }
>
On Thu, 3 May 2001, Philippe Cizaire wrote:
> Alexandre Oliva wrote:
> >
> > On May 3, 2001, Philippe Cizaire <pci@silicomp.com> wrote:
> >
> > > It works fine (but it costs me 2 uneeded temporaries that lead to at
> > > least 4 syscalls... snif).
> >
> > Huh? It shouldn't require any additional temporaries. How does the
> > new member function look like?
>
> in class TKeeper :
> TKeeper &This(void) { return *this; }
>
>
> TKeeper TKeeped::New(void)
> {
> return TKeeper(* new TKeeped).This();
> }
>
> int main(void)
> {
> {
> printf("before\n");
> TKeeper keeper(TKeeped::New().This());
> printf("after\n");
> }
>
Sorry, for a late reply but there are several possibilities to overcome
temporaries. First of all the TKeeper(* new TKeeped).This() is a bit
strange to me. Lets see if we can achieve the same thing with standart c++
operations, that you don't have to rename things like New and This.
solution a) this may be a default operation for TKeeper. Since you
never see the TKeeped object outside TKeeper, you can
create it silently in your constructor:
TKeeper::TKeeper()
:
keeped(*new TKeeped)
{
Init();
}
solution b) of course it should be possible to connect to another TKeeped
object. This should be done through your constructor
TKeeper::TKeeper( TKeeped& k ) ...
but you should never need to call it with an *unnamed* object.
In the main function this should look like:
TKeeped tk;
TKeeper tr(tk);
or
TKeeped* tk = new TKeeped;
TKeeper tr(*tk);
solution c) the operators New and This are simply dereferencing operations
for the this() and new operators of standart c++. By the constructor above
solves the problem of your New because it reduces to
TKeeped::New() { return TKeeper; }
but the real return value to reduce temporary object should be TKeeper&:
TKeeper& TKeeped::New()
{
/* I like to split lines, which can make clearer what we are doing */
TKeeped* tk = new TKepeed;
return TKeeper(*tk);
}
solution d) the solution of a) introduced a new constructor. We can render
the old and the new one together to one again:
TKeeper::TKeeper( TKeeped* td=0 )
:
keeped( (td) ? td : *new TKeeped )
{
Init();
}
In honour of good old ansi-c, it is often useful to use a pointer
instead of a reference, because it can be checked against 0. The
type safety isn't touched, because with casting we can also
kill a reference, and the c++ compiler also warns us about implicit
misused pointers.
Please let me know if you have any arguments left against these solutions ?
CU INGO