This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Not Const Temporaries




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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]