Topic: Swapping STL Constructors


Author: rado42@my-deja.com
Date: 1999/06/28
Raw View
Hi all,

I'd like to make a proposal of extending STL containers a bit.

As you know, when you return something, the returned object is
initialized (i.e. 'constructed') with the return value.

T t;
return t; // calls T(T)

Sometimes constructing of an object might be very expensive.
STL containers are such a case.

In such cases you might want pass an argument by reference instead
of 'returning' it:
void f (T& t)
{
//do whatever with 't'
...

This approach has the following disadvantages:
-The program may become less clear: if the purpos of a function is
to 'create' an object, the most natural way to express it is to
'return' it.
-Bugs might arrise, because you are not sure about the initial
 state of the object peing passed.

STL containers have a good property which might be helpfull
in this situation:

Container::swap (Container& with);

So I am using this hack:

template <class StlContainer>
class SwapReturn: public StlContainer
{
public:
SwapReturn (StlContainer &from)
   : StlContainer()
   {
   this->swap (from);
   }
};

and it is used like e.g.

SwapReturn<MyVector> f()
{
MyVector x;
do something wit x
return x;
}

(see more on http://members.tripod.com/radosoft/CppTips/SwapReturn.htm)
=================
THE PROPOSAL

What I would like to suggest is:
add additional  constructor of all STL containers, which
does the same job. It might look like this:

enum DoSwap { no_swapping, swapping };

Container::Container (Container& from, DoSwap do_swap)
{
if (do_swap == no_swapping)
   new (this) Container (from); // call usual copy constructor
else
   this->swap (from);
}


===========
How about it?




Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/06/28
Raw View
On 28 Jun 99 13:20:34 GMT, rado42@my-deja.com <rado42@my-deja.com> wrote:

>As you know, when you return something, the returned object is
>initialized (i.e. 'constructed') with the return value.
>
>T t;
>return t; // calls T(T)
>
>Sometimes constructing of an object might be very expensive.
>STL containers are such a case.

Rather than invent new and complicated language features to avoid
copying objects, push your compiler vendor to do the return value
optimization.


>In such cases you might want pass an argument by reference instead
>of 'returning' it:
>void f (T& t)
>{
>//do whatever with 't'
>...
>
>This approach has the following disadvantages:
>-The program may become less clear: if the purpos of a function is
>to 'create' an object, the most natural way to express it is to
>'return' it.
>-Bugs might arrise, because you are not sure about the initial
> state of the object peing passed.

Good analysis.


>STL containers have a good property which might be helpfull
>in this situation:
>
>Container::swap (Container& with);
>
>So I am using this hack:
>
>template <class StlContainer>
>class SwapReturn: public StlContainer
>{
>public:
>SwapReturn (StlContainer &from)
>   : StlContainer()
>   {
>   this->swap (from);
>   }
>};
>
>and it is used like e.g.
>
>SwapReturn<MyVector> f()
>{
>MyVector x;
>do something wit x
>return x;
>}

This code is malformed.  If the compiler does not perform the return
value optimization, then SwapReturn::SwapReturn(const SwapReturn&) is
called and the functions behaves as expected.  But if the compiler
does the return value optimization (meaning that it creates 'x'
directly in the return space, and does not destroy or copy 'x' at
the point of return), then SwapReturn::SwapReturn(const SwapReturn&)
is not called, and the function does not behave as expected.


>
>What I would like to suggest is:
>add additional  constructor of all STL containers, which
>does the same job. It might look like this:
>
>enum DoSwap { no_swapping, swapping };
>
>Container::Container (Container& from, DoSwap do_swap)
>{
>if (do_swap == no_swapping)
>   new (this) Container (from); // call usual copy constructor
>else
>   this->swap (from);
>}
>
>
>===========
>How about it?

But how do you call this constructor.
   return T; // may call T::T(const T&), not T::T(const T&, bool)
The only way I can think of is to give the constructor a default
argument, thereby turning it into a copy constructor.
   T::T(const T&, bool swap=true);
But most times we'll want
   T::T(const T&, bool swap=false);
Alas, there is no logical default argument.


Once again, push your compiler vendor to do the return value
optimization.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.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              ]