|
Boost : |
From: Kevin S. Van Horn (Kevin.VanHorn_at_[hidden])
Date: 2002-11-01 10:24:42
I wrote:
> What you're missing here is that if I, as the implementor, declare
> the argument to bee foo_t const &, it will be because I do not
> intend to make a copy, and there are then no copy efficiency
> concerns for you, the user, to worry about. On the other hand, if I
> declare it to be foo_t, this will only be because I need to create
> _and_ _take_ _ownership_ _of_ an actual copy
to which David Abrahams responded:
> I think you're confused. The copy is owned by the virtual machine,
> since it gets created on the stack. Usually, "take ownership of" only
> applies to heap objects whose lifetimes can be managed by their
> owners.
Not necessarily: consider use of swap and move constructors (or, more
properly, Andrei's MOJO techique for approximately implementing move
constructors). Both of these allow us to "take ownership of" a temporary, or
at least its internals. (OK, strictly speaking, this is not what is usually
meant by "take ownership"; I guess I should have chosen my terminology more
carefully.) This all goes back to the discussion Andrei started a couple of
weeks ago about move constructors and MOJO. For example, consider the
canonical strongly exception safe assignment operator:
X& operator=(X const & x) {
X tmp(x);
tmp.swap(*this);
return *this;
}
As Andrei pointed out, if a temporary gets bound to x, then we have two
copies. An alternative is
X& operator=(X x) {
x.swap(*this);
return *this;
}
which involves fewer copies is a temporary gets bound to x, and the same
number of copies as the first implementation for "x1 = x" if x is an lvalue.
The point of all this is that I, as an implementor, should have the freedom to
fiddle with such implementation details without changing the specification of
the class, and I cannot do this if the signature of the operation is fixed in
the specification instead of using valid expressions to specify the operation.
Glen Knowles added:
> But I see little point, is there any practical difference between:
>
> void f(const T& a) {
> T work(a);
> // play with work copy
> }
>
> and
>
> void f(T work) {
> // play with work
> }
>
> for types where const T& would be considered? (larger then a pointer
> and/or with an explicit constructor). Both forms copy construct "work".
The difference lies in the case f(e), where e is an rvalue (e.g., an
expression such as makeT(), where makeT is declared as "T makeT();". In this
case your first alternative involves an extra copy.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk