Topic: Proposal: Exchangeable versus Assignable
Author: Johannes Brodwall <jhannes@my-deja.com>
Date: 2000/02/26 Raw View
This is a summary of this discussion so far.
- I have proposed a change where swapping elements in a
container is used instead of copying. This is especially
useful for reallocation of containers, as copying can have
more unexpected side-effects than swapping.
- Christopher Eltscha pointed out some potential problems
with this approach
<38B245CF.A09339D5@physik.tu-muenchen.de>: The canonical
swapping function is inefficient compared to using the copy
constructor. He suggested a move constructor/operator in
the C++ language to solve this and other problems.
- Bill Wade <88k00o$5ag@library1.airnews.net> pointed out
that a swap based set of containers would have a strange
semantics and implementation for many member functions. He
used Sequence::Sequence<T>(size_type n, T t) as example. I
feel like adding resize(), push_back(), push_front() and
insert().
My original issue was to allow types with expensive (e.g.
nested containers), or undefined (e.g. non-counted smart
pointers) copy semantics to function better with standard
containers. I saw, and still see, the fact that the
standard does not give any guarantees on when the copy
constructor is called as the root cause of this problem. In
practice, this is only a problem with vector and deque, but
there is no guarantee.
The same thing applies to reordering sequence algorithms
(e.g. swap, random_shuffle).
As Christopher Eltscha pointed out, the solution is not
swap, but move. Move has the additional benefit of
providing an efficient swap. As Bill Wade pointed out, an
copy-less container cannot be created without severely
changing the semantics, especially when inserting new
elements.
Postconditions of move(dest, src):
- dest should have the same /contents/ as src had on entry.
- destroying src should not affect dest in any way.
- src can be assigned to, moved to, or destroyed.
- One of (still open):
- src is EITHER equal to dest, or the default value of
the type, or
- src's content is undefined.
I agree with Christopher Eltscha that the wanted semantics
are move, not swap. I also agree with Bill Wade that not
all functions work well without contents being Assignable.
I feel the right thing to do would be to extend the usage of
the containers with move semantics. The least committing
way of doing this, is to extend the allocator object with a
"move" function (default implementation: Like "construct").
Extending the language with "move" constructor/operator is
also a possibility. A container should then be able to own
objects that are not Assignable, as long as they are
Moveable. Populating the container with such a type in the
first place will require some extra work, but should be
doable. Most likely, the compiler should refuse to compile
usage of push_back/push_front etc.
In additions, the standard should require all reordering
algorithms (sort, random_shuffle, iter_swap, swap_ranges,
rotate etc.) to use moving/swapping behavior, so that it
could be done with non-Assignable objects.
This will:
- Allow for a greater range of objects to be used in
containers (objects with no clear copy semantics, like
uncounted smart pointers).
- Allow for greater efficiency with large objects (examples:
nested containers).
- Remove unexpected copies in the case of reallocation.
Personally, these problems pop up so often in my code that
it hinders my use of the library. I think it is reasonable
for the standard library to support these situations.
The change will, as far as I can understand, introduce no
problems with backwards-compatibility. The extra complexity
can safely be ignored, unless it is needed. Unlike the
original proposal of using swap, it introduces no extra
run-time penalty, as "copy" is a legal implementation of
"move". As opposed to "swap"-containers, "move" containers
do not require their contents to be Default Constructible
[1].
Thank you for your time,
Johannes Brodwall
[1]: Thanks to James Kuyper for pointing out that this is
not a requirement with the standard.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: "Bill Wade" <bill.wade@stoner.com>
Date: 2000/02/28 Raw View
Johannes Brodwall wrote in message <8967ui$qs1$1@nnrp1.deja.com>...
>This is a summary of this discussion so far.
A pretty good summary. I think it is worth noting that you can often get
the safer (fewer surprises) behavior of 'copy' semantics with almost the
performance of 'move' semantics with a classes that perform copy on write
(COW). In the case where both the source and destination are accessed, COW
provides copy semantics. In the case where only one of them is later
accessed, COW can often be only slightly more expensive than a pure move.
For applications where the "natural" interface involves copying large
containers around, I have found that COW (for the container as a whole) can
work very well.
If you're not used to using/implementing COW objects, some things to watch
out for:
1) Avoid interfaces that provide references to underlying data.
References to small proxy objects allow COW to "do its thing" better. A
corollary: Once some external code has a real reference to underlying data,
the data is unsharable (unless an event occurs that officially makes the
reference invalid).
2) Herb Sutter did a GOTW that discussed COW strings in a multi-threaded
(MT) environment (there is a serious aliasing issue when implementing MT
COW). Some of the posts (in comp.lang.c++.moderated) that discussed the
GOTW showed some nice MT COW optimizations.
HTH
---
[ 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: Johannes Brodwall <jhannes@my-deja.com>
Date: 2000/02/24 Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
> Johannes Brodwall wrote:
>
> > I can not see how this would happen. I realize that my
> > original posting was not very clear on this, but I only want
> > to propose the use of swap in league of copy assignment
> > where swap is the correct semantics, but copy assignment is
> > used for implementing the swap (e.g. vector reallocation).
> > In the situations where Assignment is the wanted semantics,
> > I agree that swapping is not appropriate.
>
> How would you use swap in vector reallocation?
> The only way I see is to first default-construct an object
> at the destination, then swap that with the object to move,
> and finally destruct the object on the original place.
>
> This is not guaranteed to be faster (default construction
> may even take more time for some objects, f.ex. if it
> involves memory allocation, while copying would just modify
> a reference count), but has the additional constraint that
> the object must be default-constructible.
I was aware of the fact that with the proposed change, the
contents had to be Default Constructible, but I assumed that
this was a restriction already. At least for the Containers
with a reserve function, this is a requirement. I did not
think about the problem with the extra time, however. Thank
you for pointing this out to me.
Both of these problems can probably be eliminated by
extending the standard Allocator class with a "move"
operator instead of my original proposal with using swap.
The move operator should have as only postcondition that the
destination is now equal to the original value of the
source, and that destructing the source will not affect the
destination. Default implementation: One copy constructor.
Custom implementation: Default Constructor plus Swap. I
am wondering if all calls to allocator::construct(pointer p,
T const& val) could be exchanged with calls to
allocator::move(pointer p, T& val).
> The _real_ thing missing (not just to the STL, but to C++
> in general), IMHO is the distinction between copy and move.
> If we had a move constructor in addition to the copy
> constructor (and possibly also a move operator), then
> this could generally be more efficient than copy. In addition,
> quite often (I even think, always) a move can be made guaranteed non-
throwing,
> even where copy cannot.
>
> This would allow to
> - create an generic implementation of an _optimal_ swap, which
> in addition can be made non-throwing for most (if not all)
> classes
> - implement optimal reallocation in containers
> - Use move instead of copy everywhere where currently the copy
> may be optimized away (of course, completely optimizing away
> should still be allowed).
> The last one is why move has to be in the language rather than
> the library.
I agree that this seems to be looking like a better option
than using swap more (perhaps making it a part of the core
language). It will get away with the extra overhead of
constructing a uninitialised object, plus it will solve some
other issues at the same time.
I see one major problem with the move operator, in addition
to the fact that it is probably harder to change the
language than the library. You seem to be hinting a little
at this problem yourself:
> The move constructor/operator would leave the old object in a state
where at
> least the following operations are safe:
> - Destruction
> - Assignment to it
> - Move to it
Somehow, this all sounds like it will introduce potensial
for error. The semantics of what happens to both objects
after a swap are much clearer. As far as I can understand
it, Moving an object will either make the old object
identical to the Default Constructible version of itself, or
introduce an undefined situation, namely what happens when
you try to use it in other ways than you indicate? If there
is something C++ does not need (IMHO) it is more undefined
situations.
Sincerely,
Johannes Brodwall
--
"Have you given your computer a hug today?"
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: 2000/02/24 Raw View
Johannes Brodwall wrote:
>
> Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
>
> > Johannes Brodwall wrote:
> >
> > > I can not see how this would happen. I realize that my
> > > original posting was not very clear on this, but I only want
> > > to propose the use of swap in league of copy assignment
> > > where swap is the correct semantics, but copy assignment is
> > > used for implementing the swap (e.g. vector reallocation).
> > > In the situations where Assignment is the wanted semantics,
> > > I agree that swapping is not appropriate.
> >
> > How would you use swap in vector reallocation?
> > The only way I see is to first default-construct an object
> > at the destination, then swap that with the object to move,
> > and finally destruct the object on the original place.
> >
> > This is not guaranteed to be faster (default construction
> > may even take more time for some objects, f.ex. if it
> > involves memory allocation, while copying would just modify
> > a reference count), but has the additional constraint that
> > the object must be default-constructible.
>
> I was aware of the fact that with the proposed change, the
> contents had to be Default Constructible, but I assumed that
> this was a restriction already. At least for the Containers
> with a reserve function, this is a requirement. I did not
> think about the problem with the extra time, however. Thank
> you for pointing this out to me.
>
> Both of these problems can probably be eliminated by
> extending the standard Allocator class with a "move"
> operator instead of my original proposal with using swap.
>
> The move operator should have as only postcondition that the
> destination is now equal to the original value of the
> source, and that destructing the source will not affect the
> destination. Default implementation: One copy constructor.
> Custom implementation: Default Constructor plus Swap. I
> am wondering if all calls to allocator::construct(pointer p,
> T const& val) could be exchanged with calls to
> allocator::move(pointer p, T& val).
>
> > The _real_ thing missing (not just to the STL, but to C++
> > in general), IMHO is the distinction between copy and move.
> > If we had a move constructor in addition to the copy
> > constructor (and possibly also a move operator), then
> > this could generally be more efficient than copy. In addition,
> > quite often (I even think, always) a move can be made guaranteed non-
> throwing,
> > even where copy cannot.
> >
> > This would allow to
> > - create an generic implementation of an _optimal_ swap, which
> > in addition can be made non-throwing for most (if not all)
> > classes
> > - implement optimal reallocation in containers
> > - Use move instead of copy everywhere where currently the copy
> > may be optimized away (of course, completely optimizing away
> > should still be allowed).
>
> > The last one is why move has to be in the language rather than
> > the library.
>
> I agree that this seems to be looking like a better option
> than using swap more (perhaps making it a part of the core
> language). It will get away with the extra overhead of
> constructing a uninitialised object, plus it will solve some
> other issues at the same time.
>
> I see one major problem with the move operator, in addition
> to the fact that it is probably harder to change the
> language than the library. You seem to be hinting a little
> at this problem yourself:
>
> > The move constructor/operator would leave the old object in a state
> where at
> > least the following operations are safe:
> > - Destruction
> > - Assignment to it
> > - Move to it
>
> Somehow, this all sounds like it will introduce potensial
> for error. The semantics of what happens to both objects
> after a swap are much clearer. As far as I can understand
> it, Moving an object will either make the old object
> identical to the Default Constructible version of itself, or
> introduce an undefined situation, namely what happens when
> you try to use it in other ways than you indicate? If there
> is something C++ does not need (IMHO) it is more undefined
> situations.
If not overwritten, move just copies. Copying leaves the
old object in a well defined state (unless the class is
mis-designed).
If overwritten, move leaves the object in exactly that state
the user decides it to leave in. That is, the _writer_
defines which operations are safe and which aren't.
The above restrictions would be what the compiler/std library
assume. That is, if the programmer writes a move that
violates those conditions, he's quite guaranteed to produce
a bug. Since compiler and standard library would not make any
other assumptions, making other operations undefined for
moved away objects would be no harm unless they are explicitly
used. But that doesn't mean they have to be undefined - it's
a design choice (just as it is a design choice to construct
objects in an "error state" if construction fails).
The above is not an introduction of undefined behaviour, but
rather a requirement of what operations may _not_ cause
undefined behaviour, independent from design choices.
That is, if assignment _from_ a moved-away object is undefined,
it may be a bad design. But if assignment _to_ a moved-away
object is undefined, it is a program bug.
Given that the default behaviour doesn't introduce undefined
behaviour, if any undefined behaviour occurs due to move,
the only one responsible for this is the programmer/class
designer.
Indeed, you yourself have stated the destructible condition
for an allocator move function as only condition.
I've added the assignable and "move-to"able conditions, because
esp. the latter would be crucial for a 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 ]
Author: James Kuyper <kuyper@wizard.net>
Date: 2000/02/24 Raw View
Johannes Brodwall wrote:
....
> I was aware of the fact that with the proposed change, the
> contents had to be Default Constructible, but I assumed that
> this was a restriction already. At least for the Containers
> with a reserve function, this is a requirement. I did not
Citation please? Section 20.1.4 pointes out that "Certain container
class member function signatures specify the default constructor as a
default argument." and therefore "T() must be a well defined expression
(8.5)", but only "if one of those signatures is called using the default
argument (8.3.6)."
AFAIK, there's no connection made anywhere between reserve() and default
constructability. There shouldn't be. The reserve() member function may
call Allocator::allocate(), but has no need to call
Allocator::construct() until it can do it as copy construction rather
than as default construction. No container ever needs to default
construct any contained elements, except when using the functions
referred to in section 20.1.4.
---
[ 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: Stephen Cleary <scleary@jerviswebb.com>
Date: 2000/02/25 Raw View
Christopher Eltschka wrote:
> Johannes Brodwall wrote:
> >
> > Frans Meijer wrote:
> > > But that would severely change the semantic. Assignment means
> > > that what's left of the '=' becomes what is right of the
> > > '='. Swapping or exchanging would have tremendous impact.
> > > And likely a lot of unwanted side-effects.
I've toyed around with 'Relaxed Assignable' and 'Relaxed
CopyConstructible' requirements that are like the STL req's only they
require a non-const source, and the source may be modified.
In fact, I've made a 'Relaxed Container', which can hold Relaxed objects
; the main problem is that for every function taking 'const T &' in the
Standard, we have to provide two copies of in the Relaxed Container.
However, this can lead to code bloat. I've (mostly) gotten around the
problem by using call_traits, a traits class that specifies how objects
of a given type should be passed to functions (builtins by value,
default is const reference; for Relaxed objects, specialize to non-const
reference).
>
> The _real_ thing missing (not just to the STL, but to C++
> in general), IMHO is the distinction between copy and move.
> If we had a move constructor in addition to the copy
> constructor (and possibly also a move operator), then
> this could generally be more efficient than copy. In addition,
> quite often (I even think, always) a move can be made guaranteed
> non-throwing, even where copy cannot.
>
Bravo! I agree completely. I have a 'move' operation in my personal
library, and have often thought that it should be used in certain places
by the language itself.
> Note that since the default action of move would be to copy
> (i.e. unless you write your own move constructor/move operator,
> it calls the copy constructor/copy assignment operator), it
> still could be introduced in the next version of the standard
> without breaking compatibility (programs not explicitly using
> this feature - that is, all current programs - won't notice
> a difference).
Yes. 'move' would be a copy, with const source or not. My 'move'
algorithm would also specialize for std container types a default
construction followed by swap.
> The move constructor/operator would leave the old object in a state
> where at least the following operations are safe:
> - Destruction
> - Assignment to it
> - Move to it
This is where I disagree. I designed my 'move' so that it included the
constructor and destructor. In other words, Destruction and Assignment
would be illegal, but it would allow Construction or Move.
> If all you want is to put auto_ptr<T> into a container, the
> simplest option would be to partially specialize the containers
> on auto_ptr<T>. Since auto_ptr<T> is the only class with this
> strange copy semantics, this would solve the problem completely.
No way. I use the concept of "ownership" in several objects that I
create, managing resources from database transaction handles to window
handles. They all have non-const Assignable/CopyConstructible
semantics, and many could benifit from Relaxed Containers.
Just my 2 bits :)
-Steve
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: Johannes Brodwall <jhannes@my-deja.com>
Date: 2000/02/22 Raw View
[Initial posting omitted]
Frans Meijer <kanga_roo@my-deja.com> wrote:
> But that would severely change the semantic. Assignment means
> that what's left of the '=' becomes what is right of the
> '='. Swapping or exchanging would have tremendous impact.
> And likely a lot of unwanted side-effects.
I can not see how this would happen. I realize that my
original posting was not very clear on this, but I only want
to propose the use of swap in league of copy assignment
where swap is the correct semantics, but copy assignment is
used for implementing the swap (e.g. vector reallocation).
In the situations where Assignment is the wanted semantics,
I agree that swapping is not appropriate.
If this was not what you meant, I would appreciate an
elaboration of your argument.
> But you can always implement a smart-pointer with that
> behaviour and see what happens...
The auto_ptr in STL has behavior very close to what I want.
The problem with auto_ptr is that it's copy assignment and
copy constructor has unwanted side effects. A swap function
over the auto_ptr would not have this problem, though. What
irritates me to no extent is the fact that when you try to
put a smart pointer (like auto_ptr), into a Container,
things will break down because when the container is sorted
or reallocated, because of the copy constructor. Had the
default constructor and swap been used, this would not have
been a problem.
So: The auto_ptr is (could be made to be) Exchangeable, but
not Assignable. The current situation is that the auto_ptr
is forbidden as a container member, while this could've been
avoided. The same argument applies to large objects as
container members, such as nested containers.
Sincerely
Johannes Brodwall
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: 2000/02/23 Raw View
Johannes Brodwall wrote:
>
> [Initial posting omitted]
>
> Frans Meijer <kanga_roo@my-deja.com> wrote:
> > But that would severely change the semantic. Assignment means
> > that what's left of the '=' becomes what is right of the
> > '='. Swapping or exchanging would have tremendous impact.
> > And likely a lot of unwanted side-effects.
>
> I can not see how this would happen. I realize that my
> original posting was not very clear on this, but I only want
> to propose the use of swap in league of copy assignment
> where swap is the correct semantics, but copy assignment is
> used for implementing the swap (e.g. vector reallocation).
> In the situations where Assignment is the wanted semantics,
> I agree that swapping is not appropriate.
How would you use swap in vector reallocation?
The only way I see is to first default-construct an object
at the destination, then swap that with the object to move,
and finally destruct the object on the original place.
This is not guaranteed to be faster (default construction
may even take more time for some objects, f.ex. if it
involves memory allocation, while copying would just modify
a reference count), but has the additional constraint that
the object must be default-constructible.
The _real_ thing missing (not just to the STL, but to C++
in general), IMHO is the distinction between copy and move.
If we had a move constructor in addition to the copy
constructor (and possibly also a move operator), then
this could generally be more efficient than copy. In addition,
quite often (I even think, always) a move can be made guaranteed
non-throwing, even where copy cannot.
This would allow to
- create an generic implementation of an _optimal_ swap, which
in addition can be made non-throwing for most (if not all)
classes
- implement optimal reallocation in containers
- Use move instead of copy everywhere where currently the copy
may be optimized away (of course, completely optimizing away
should still be allowed).
The last one is why move has to be in the language rather than
the library.
Note that since the default action of move would be to copy
(i.e. unless you write your own move constructor/move operator,
it calls the copy constructor/copy assignment operator), it
still could be introduced in the next version of the standard
without breaking compatibility (programs not explicitly using
this feature - that is, all current programs - won't notice
a difference).
The move constructor/operator would leave the old object in a state
where at least the following operations are safe:
- Destruction
- Assignment to it
- Move to it
(That is, basically the same operations which are legal on
uninitialized objects of built-in type)
>
> If this was not what you meant, I would appreciate an
> elaboration of your argument.
>
> > But you can always implement a smart-pointer with that
> > behaviour and see what happens...
>
> The auto_ptr in STL has behavior very close to what I want.
> The problem with auto_ptr is that it's copy assignment and
> copy constructor has unwanted side effects. A swap function
> over the auto_ptr would not have this problem, though. What
> irritates me to no extent is the fact that when you try to
> put a smart pointer (like auto_ptr), into a Container,
> things will break down because when the container is sorted
> or reallocated, because of the copy constructor. Had the
> default constructor and swap been used, this would not have
> been a problem.
>
> So: The auto_ptr is (could be made to be) Exchangeable, but
> not Assignable. The current situation is that the auto_ptr
> is forbidden as a container member, while this could've been
> avoided.
If all you want is to put auto_ptr<T> into a container, the
simplest option would be to partially specialize the containers
on auto_ptr<T>. Since auto_ptr<T> is the only class with this
strange copy semantics, this would solve the problem completely.
Moreover, this could be optimized by using auto_ptr<T> only in
the interface, while internally working with raw pointers (and
providing the semantics through container member functions).
Note that other smart pointers don't have this problem, since
they have normal copy semantics.
> The same argument applies to large objects as
> container members, such as nested containers.
It's not the same argument: For large objects, you only get
optimisations (and even then, only if they provide an
optimized swap and cheap default construction). move would
help here, too; another solution would be type traits which
implement the most efficient moving method.
---
[ 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: "Bill Wade" <bill.wade@stoner.com>
Date: 2000/02/24 Raw View
jhannes@my-deja.com wrote in message <88dq3g$trs$1@nnrp1.deja.com>...
>(Note: This posting uses the vocabulary in SGI's STL doc
>http://www.sgi.com/Technology/STL/)
>
>I have found the restriction of container members having to
>be "Assignable" to be restrictive to the point of thwarting
>an otherwise sound design.
>To remedy this situation, I propose the notion of
>Exchangeable types. An Exchangeable type is an type for
>which the expression swap(type&, type&) is defined.
You may want to build your own "Exchangeable" container library. There are
some problems with restricting existing containers to use swap() rather than
assignment or copy construction.
1) There are many classes for which swap is three times as expensive as
assignment. If containers use swap instead of assignment, simple cases end
up paying for something they don't need.
2) Some container member functions and constructors clearly require copy
(rather than swap) semantics. Consider
Sequence::Sequence<T>(size_type n, T t);
It would be interesting to see some containers that worked in an environment
where swap() was preferred to assignment.
---
[ 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: jhannes@my-deja.com
Date: 2000/02/17 Raw View
(Note: This posting uses the vocabulary in SGI's STL doc
http://www.sgi.com/Technology/STL/)
I have found the restriction of container members having to
be "Assignable" to be restrictive to the point of thwarting
an otherwise sound design. There are two situations, in
particular, where this ruins the design:
- Large objects. Most notably objects containing other
containers. Although these are, strictly speaking,
Assignable, copy assignment can be a performance problem
(I suspect this to be an important part of the cause of
the bad statistics in Dan Saks's "C++ Theory and
Practice" column the January Y2K Edition of C/C++ Users
Journal).
- Objects with no clear copy semantics. These are the
tricky ones. Having to use C-structs that own memory
(in order to interface with other languages), I find it
difficult to use Standard Containers. Another class
that is not Assignable, but that people often want to
place in a container is the auto_ptr.
To remedy this situation, I propose the notion of
Exchangeable types. An Exchangeable type is an type for
which the expression swap(type&, type&) is defined.
The Exchangeable types are, of course, a subset of
Assignable, meaning that such a change will be compatible
with the existing standard. The default (template)
implementation of swap gives all Assignable types an
implementation of swap. For types where this implementation
is not sufficient, an explicit instantiation of swap can be
provided.
Exchangeable types are relevant as a replacement for all
Containers, most Sorting algorithm functions, and some
Mutating algorithm functions. The list of functions is
easy, if tedious, to make. In all these cases, two elements
can be swapped instead of creating extraneous copies.
As far as I can see, there is no reason to insist on the
stronger concept of Assignable in these cases. The
Exchangeable Concept allows for a wider range of types to be
used efficiently. The extra complexity it introduces is
safe to for users to ignore as long as it is not needed, as
Exchangeable is a true subtype of Assignable.
Sincerely
Johannes Brodwall
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: Frans Meijer <kanga_roo@my-deja.com>
Date: 2000/02/18 Raw View
In article <88dq3g$trs$1@nnrp1.deja.com>,
jhannes@my-deja.com wrote:
> (Note: This posting uses the vocabulary in SGI's STL doc
> http://www.sgi.com/Technology/STL/)
>
> I have found the restriction of container members having to
> be "Assignable" to be restrictive to the point of thwarting
> an otherwise sound design. There are two situations, in
> particular, where this ruins the design:
>
> - Large objects. Most notably objects containing other
> containers. Although these are, strictly speaking,
> Assignable, copy assignment can be a performance problem
> (I suspect this to be an important part of the cause of
> the bad statistics in Dan Saks's "C++ Theory and
> Practice" column the January Y2K Edition of C/C++ Users
> Journal).
>
> - Objects with no clear copy semantics. These are the
> tricky ones. Having to use C-structs that own memory
> (in order to interface with other languages), I find it
> difficult to use Standard Containers. Another class
> that is not Assignable, but that people often want to
> place in a container is the auto_ptr.
>
> To remedy this situation, I propose the notion of
> Exchangeable types. An Exchangeable type is an type for
> which the expression swap(type&, type&) is defined.
>
> The Exchangeable types are, of course, a subset of
> Assignable, meaning that such a change will be compatible
> with the existing standard. The default (template)
> implementation of swap gives all Assignable types an
> implementation of swap. For types where this implementation
> is not sufficient, an explicit instantiation of swap can be
> provided.
>
> Exchangeable types are relevant as a replacement for all
> Containers, most Sorting algorithm functions, and some
> Mutating algorithm functions. The list of functions is
> easy, if tedious, to make. In all these cases, two elements
> can be swapped instead of creating extraneous copies.
>
> As far as I can see, there is no reason to insist on the
> stronger concept of Assignable in these cases. The
> Exchangeable Concept allows for a wider range of types to be
> used efficiently. The extra complexity it introduces is
> safe to for users to ignore as long as it is not needed, as
> Exchangeable is a true subtype of Assignable.
>
But that would severly change the semantic. Assignment means that
what's left of the '=' becomes what is right of the '='. Swapping or
exchanging would have tremendous impact. And likely a lot of unwanted
side-effects.
But you can always implement a smart-pointer with that behaviour and
see what happens...
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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 ]