Topic: buldozer_copy" ?


Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/11/30
Raw View
<lafortne@math.princeton.edu> wrote:
> I sometimes have the desire to copy from 'source' to 'dest' in the
> most efficient way possible, without caring about the values that
> source will hold after that copy. Clearly 'dest = source;' should do
> the job, but ...

Siemel Naran wrote:
> We have "std::copy".
> Whenever appropriate, an invocation of std::copy should reduce to
> the more efficient memcpy or, when appropriate, memmove (which is
> even faster as it assumes that the regions don't overlap).
> Most compilers don't yet do this smart optimization.

It's a minor nit, but you've got it backwards; std::memcpy()
guarantees fast copying, while std::memmove() guarantees correct
handling of overlapping objects.  If you're sure the source and
target objects don't overlap, then use memcpy(), otherwise use
memmove().

Compilers are free to implement POD copies as they see fit; they
might call memcpy()/memmove(), or they might generate LOOP
instructions in assembler, or they might copy each member
individually, or they might do something totally different.
The advantage of POD types is that they can be copied byte-for-byte
very efficiently.

-- David R. Tribble, dtribble@technologist.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: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1998/11/30
Raw View
On 30 Nov 1998 21:27:08 GMT, David R Tribble

>Compilers are free to implement POD copies as they see fit; they
>might call memcpy()/memmove(), or they might generate LOOP
>instructions in assembler, or they might copy each member
>individually, or they might do something totally different.
>The advantage of POD types is that they can be copied byte-for-byte
>very efficiently.

But the optimization applies also to non POD types.  Specifically any
class with a trivial copy ctor, because such a class is essentially POD
like.  Like class complex<double>.  Or even complex<complex<double>>.

According to the standard, if a class has a ctor, it is not POD.
But changing the definition of POD to allow complex<double> to be
a POD would be nice: any type with a trivial copy ctor and dtor.
This way, complex<double> can be a member of a union.

--
----------------------------------
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              ]






Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1998/11/27
Raw View
On 26 Nov 98 11:37:11 GMT, Marc-Andre lafortune

>Indeed, this is what I will use. Note though that the fact that it is not
>included in the standard (a) obliges me to specialize it for vector<>, list<>,
>... (b) but especially will not be efficient if used with other containers I
>don't know about, since their creators didn't know about my transfer

Fine.

>            I'm not sure what I said is clear, but I believe the reason
>std::swap exists is not so much because it's usual form (T temp = x; x = y; y
>= temp) is useful but much more because it may be much more efficient in some
>cases (vector, ...) and thus should be a _standard_ function that everyone can
>rely on _and_ specialize for their own classes...

Fine.  Swap is common.  Every comparison sort function will use it,
and some others will too.  But this transfer function seems
basically like an optimized operator=.  Ideally, we don't want
general users to use it.  However, here's an idea for the
optimizer.  If in the assignment "a=b" the compiler can see that
'b' is going to go out of scope, it can synthesize its own
efficient operator= and use that instead.  Don't know whether
this optimization is really possible, but it surely makes sense.
This might be something to talk about more.

However, when sorting arrays is very common, I follow this design
pattern.  Make an object that is essentially a pointer to the
original object.  Then instantiate a container of this pointer
or wrapper object.  Eg,
   class Ptr; // contains an Object*
   std::vector<Ptr>;
Now we can sort this new container in all sorts of ways without
fear of time penalty.  I've used this idea with much success.
The actual object was a class Activity, and the pointer object
was a class Remind.  Yes, it is important to have good names,
better than 'Ptr' above.  The class Activity just stores raw
data.  The class Remind stores a pointer to an Activity and
some other stuff, like an undo stack.


>  I'm not sure I understand; in a way, a "transfer" of information is not
>(necessarily) the same as a "copy" of information and thus it doesn't strike
>me as surprising that we might want both of these ideas.

You're right; it is conceptually different.  But most users will use it
as an optimized operator=.  We can discuss this more too.  I might be
wrong.

--
----------------------------------
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              ]





Author: Marc-Andre lafortune <lafortne@math.princeton.edu>
Date: 1998/11/26
Raw View
Siemel Naran wrote:
<Snip>

> Why not just make a template
> 'transfer' function and specialize it is necessary?
>
> template <class T> // generic
> inline T& transfer(T& destination, T& source)
> {
>      return destination=source;
> }
>
> template <class T> // partial specialization
> inline vector<T>& transfer(vector<T>& destination, vector<T>& source);
>   // more efficient implementation
>   // transfers pointers, nullifies pointers, or whatever

Indeed, this is what I will use. Note though that the fact that it is not
included in the standard (a) obliges me to specialize it for vector<>, list<>,
... (b) but especially will not be efficient if used with other containers I
don't know about, since their creators didn't know about my transfer
function... I'm not sure what I said is clear, but I believe the reason
std::swap exists is not so much because it's usual form (T temp = x; x = y; y
= temp) is useful but much more because it may be much more efficient in some
cases (vector, ...) and thus should be a _standard_ function that everyone can
rely on _and_ specialize for their own classes...

<Snip>
> It seems a little clumsy to me because it now looks like we have
> two op= functions -- one that preserves the original and one that
> does not.  My own Vector class from before used this idea for a
> while.

  I'm not sure I understand; in a way, a "transfer" of information is not
(necessarily) the same as a "copy" of information and thus it doesn't strike
me as surprising that we might want both of these ideas.

-Marc
---
[ 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: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/11/24
Raw View
=?UNKNOWN-8BIT?Q?Marc-Andr=E9?= lafortune wrote:
>
> I sometimes have the desire to copy from 'source' to 'dest' in the most
> efficient way possible, without caring about the values that source will hold
> after that copy. Clearly 'dest = source;' should do the job, but for vectors,
> using swap is much more efficient. On the other hand, if the list we're
> dealing with is a 'SomeType[1000]', that swap is 3 times slower than
> necessary. I am so happy about the existence of the standard 'swap' (since
> anyone coding some class that is easily swapable will specialize swap) I was
> wondering why there is no such 'buldozer_copy' standard function. Maybe I'm
> the only one who would use it? I would also be curious to know how people
> using it call that function. I think 'transfer_to' is the most accurate I can
> think of...

I think it's clear that the standard is missing some destructive
move function.

The implementation can do it for its own types but it won't ever
know about the semantics of user defined types.

Note that SGI C++ has a magic template, __I_don't_remember_the_name,
which indicates if a type has a trivial default ctor, copy ctor,
assignement op, or dtor. But it's completly non standard (as the
name sugests), and anyway it isn't sufficient.

IMO it's up to the compiler to suppress empty loops:

for (T* p = x; p != y; p++);

but it's the responsabillity of every class implementor (with
value semantics) to supply a move function. And the syntax and
semantics of such a function should be specified in the standard.

Also it could be nice if such a function was integrated in the
core language:

T fun ()
{
    T x, y;
    if (condition)
        return x;
    else
        return y;
}

could be compiled

void fun (storage<T> &__ret)
{
    storage<T> x, y;
    new (x) T ();
    new (y) T ();
    if (condition)
    {
        new (__ret) x.~T ();
        y.~T ();
    }
    else
    {
        new (__ret) y.~T ();
        x.~T ();
    }
}

saving one copy ctor call in both branches [the alternative
(w/o destructive construction) I see is:

T* fun ()
{
    T x, y;
    if (condition)
        return &x;
    else
        return &y;
}

but it's a bit difficult to implement:

x = fun();

is ok:

x.operator= (*__res = fun ());
__res->~T ();

but

T x = fun();
T y;

causes problems:

T* p = fun();
new (where can I put y now ?) T ();

you have to begin the new 'stack frame' after p - I don't know
if this generally possible w/o serious overhead ]

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/


[ 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: Marc-Andre lafortune <lafortne@math.princeton.edu>
Date: 1998/11/24
Raw View
Christopher Eltschka wrote:

> Marc-Andre lafortune wrote:

> > I sometimes have the desire to copy from 'source' to 'dest' in the most
> > efficient way possible, without caring about the values that source will hold
> > after that copy. Clearly 'dest = source;' should do the job, but for vectors,
> > using swap is much more efficient. On the other hand, if the list we're
> > dealing with is a 'SomeType[1000]', that swap is 3 times slower than
> > necessary. I am so happy about the existence of the standard 'swap' (since
> > anyone coding some class that is easily swapable will specialize swap) I was
> > wondering why there is no such 'buldozer_copy' standard function. Maybe I'm
> > the only one who would use it? I would also be curious to know how people
> > using it call that function. I think 'transfer_to' is the most accurate I can
> > think of...

> I would call it "move", since the original object's state may be
> nonsense after that (it just has to be safe to destruct or assign it). However,
> I'd like to have a "move constructor", which would be used by the compiler
> in those cases where today copy can be optimized away. That rule would then
> be "move construction can be optimized away".
<Snip>

I like 'move' and indeed the idea of the move constructor is very good one,
although I don't think it spares us from a move operator = (in the same way
that the copy constructor had to have it's corresponding copy operator =). In
the meantime, I guess I'll create a 'move' template...
  Thanks

-Marc



[ 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@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1998/11/25
Raw View
On 24 Nov 98 00:58:57 GMT, =?UNKNOWN-8BIT?Q?"Marc-Andr=E9?= lafortune"

>I sometimes have the desire to copy from 'source' to 'dest' in the most
>efficient way possible, without caring about the values that source will hold
>after that copy. Clearly 'dest = source;' should do the job, but for vectors,
>using swap is much more efficient. On the other hand, if the list we're
>dealing with is a 'SomeType[1000]', that swap is 3 times slower than
>necessary. I am so happy about the existence of the standard 'swap' (since
>anyone coding some class that is easily swapable will specialize swap) I was
>wondering why there is no such 'buldozer_copy' standard function. Maybe I'm
>the only one who would use it? I would also be curious to know how people
>using it call that function. I think 'transfer_to' is the most accurate I can
>think of...

OK, my first response didn't address the real question you asked.
Sorry about that.  Let me try again.  Why not just make a template
'transfer' function and specialize it is necessary?

template <class T> // generic
inline T& transfer(T& destination, T& source)
{
     return destination=source;
}

template <class T> // partial specialization
inline vector<T>& transfer(vector<T>& destination, vector<T>& source);
  // more efficient implementation
  // transfers pointers, nullifies pointers, or whatever


Now vector<T>::operator= can use the 'transfer' function.  Ie, when
copying elements from the old vector to the new, for when we resize
the array, we just use the 'transfer' function rather than the copy
ctor.  So a vector<vector<int>> would be very efficient.  What do
you think of this idea?

It seems a little clumsy to me because it now looks like we have
two op= functions -- one that preserves the original and one that
does not.  My own Vector class from before used this idea for a
while.

--
----------------------------------
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              ]





Author: =?UNKNOWN-8BIT?Q?"Marc-Andr=E9?= lafortune" <lafortne@math.princeton.edu>
Date: 1998/11/24
Raw View
I sometimes have the desire to copy from 'source' to 'dest' in the most
efficient way possible, without caring about the values that source will hold
after that copy. Clearly 'dest = source;' should do the job, but for vectors,
using swap is much more efficient. On the other hand, if the list we're
dealing with is a 'SomeType[1000]', that swap is 3 times slower than
necessary. I am so happy about the existence of the standard 'swap' (since
anyone coding some class that is easily swapable will specialize swap) I was
wondering why there is no such 'buldozer_copy' standard function. Maybe I'm
the only one who would use it? I would also be curious to know how people
using it call that function. I think 'transfer_to' is the most accurate I can
think of...
   Thanks,

- Marc.
---
[ 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: 1998/11/24
Raw View
On 24 Nov 98 00:58:57 GMT, =?UNKNOWN-8BIT?Q?"Marc-Andr=E9?= lafortune"

>I sometimes have the desire to copy from 'source' to 'dest' in the most
>efficient way possible, without caring about the values that source will hold
>after that copy. Clearly 'dest = source;' should do the job, but for vectors,
>using swap is much more efficient. On the other hand, if the list we're
>dealing with is a 'SomeType[1000]', that swap is 3 times slower than
>necessary. I am so happy about the existence of the standard 'swap' (since
>anyone coding some class that is easily swapable will specialize swap) I was
>wondering why there is no such 'buldozer_copy' standard function. Maybe I'm
>the only one who would use it? I would also be curious to know how people
>using it call that function. I think 'transfer_to' is the most accurate I can
>think of...
>   Thanks,

We have "std::copy".
Whenever appropriate, an invocation of std::copy should reduce to
the more efficient memcpy or, when appropriate, memmove (which is
even faster as it assumes that the regions don't overlap).
Most compilers don't yet do this smart optimization.

The compiler generated copy ctor and op= for trivial types like
FixedArray, Currency, Date, Time, iterator, Priority should be
a memmove behind the scenes.  I'm pretty sure compilers do this
optimization, but haven't checked it.


If swapping SomeType[1000] objects is very important -- say you
have a vector of SomeType[1000] objects -- then you should
consider using pointers to a SomeType[1000].  Then to swap two
objects you just swap pointers.  Incidentally, swap for
dynamically allocated arrays like std::vector swaps pointers
-- as the only way to get a dynamic array of SomeType objects
is to use SomeType*.  But if the vector were reference counted
then swapping can be implemented faster using the normal
{ T tmp=lhs; lhs=rhs; rhs=tmp; } method.  Anyway, there is
good reason to use a fixed array size whenever possible.

SomeType (*ptr)[1000]; // pointer to a SomeType[1000]
SomeType * ptr [1000]; // array of 1000 SomeType* objects

--
----------------------------------
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              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/11/24
Raw View
=?UNKNOWN-8BIT?Q?Marc-Andr=E9?= lafortune wrote:
>
> I sometimes have the desire to copy from 'source' to 'dest' in the most
> efficient way possible, without caring about the values that source will hold
> after that copy. Clearly 'dest = source;' should do the job, but for vectors,
> using swap is much more efficient. On the other hand, if the list we're
> dealing with is a 'SomeType[1000]', that swap is 3 times slower than
> necessary. I am so happy about the existence of the standard 'swap' (since
> anyone coding some class that is easily swapable will specialize swap) I was
> wondering why there is no such 'buldozer_copy' standard function. Maybe I'm
> the only one who would use it? I would also be curious to know how people
> using it call that function. I think 'transfer_to' is the most accurate I can
> think of...

I would call it "move", since the original object's state may be
nonsense
after that (it just has to be safe to destruct or assign it). However,
I'd
like to have a "move constructor", which would be used by the compiler
in
those cases where today copy can be optimized away. That rule would then
be
"move construction can be optimized away". The reason is that in those
cases, even if there's no possibility to really optimize that copy/move
away (for whatever reason), the move constructor could still take
advantage of the fact that the original object will cease to exist.
The compiler generated move constructor would call the copy constructor,
and so give compatibility to current behaviour. A move assignment
operator
would be nice as well.
The move constructor would also give the possibility to return objects
by
value, and at the same time forbid making real copies (that is, having
two accessible objects at the same time). Moreover, I think that move
constructors - other than copy constructors - may always be written in
a way that no exception can occur; this would allow an exception-safe
swap implementation.
---
[ 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              ]