
On Sep 27, 2004, at 2:46 AM, Thorsten Ottosen wrote:
"Howard Hinnant" <hinnant@twcny.rr.com> wrote in message news:83B293FA-1013-11D9-9D49-003065D18932@twcny.rr.com... | container<sole_ptr<T>> will have the same overhead as that demonstrated | in the Smart Container library. A big difference will be that | iterators into the container will dereference smart pointers, and not | the pointed-to elements. I also anticipate C++0X will contain some | really slick indirect_iterator types that will transform | container<sole_ptr<T>>::iterator appropriately. These will likely be | heavily influenced by (if not based on) the Boost.Iterator Library.
I assume that there will still be some differences:
1. a large part of the in this library is indirected, eg. front() in container<sole_ptr<T>> would return sole_ptr<T>
Right.
2. release() and clone() can be made faster by moving instead of using an std::auto_ptr<> as today
Yup.
3. your map iterators would be different
Right, just smart pointers to pair<const sole_ptr<T>, U>.
4. If you do intend that the interface of container<sole_ptr<T>> has the same interface as container<T>, then you loose the domain specific interface and the Clonable metaphor
Right again.
| Assuming things go just peachy, all std::containers will be move-aware | and thus able to contain move-only types like sole_ptr<T>. Also I | would like to see all in-place-mutating std:: sequence algorithms | (remove_if, unique, etc.) rewritten to deal with ranges of move-only | types as well. Such algorithms, if not rewritten for move-only types | will fail at compile time (as opposed to run time) for move-only types.
That would be nice. If all mutating algorithms would be guaranteed to call a swap and never use a copy-constructor, I think we could make an iterator for the smart containers that was indirected *and* did "the right thing" in those algorithms.
Agreed, sort of. We don't want to mandate that all algorithms call swap. That would be too expensive for some algorithms (like remove) when operating on sequences of some types (like int or complex<T>). Rather I would like to mandate that algorithms such as remove work for movable but non-copyable types. I.e. internally where remove today might say: *j = *i; it would instead have to code: *j = move(*i); This might end up calling swap for some types, if the author of that type has implemented move assignment with swap. For other types (like int, or complex<T>), there will be no move assignment, and the above change will make absolutely no difference in behavior or efficiency (right down to the assembly that is generated). All move(*i) does is tell the compiler to treat *i as an rvalue instead of an lvalue. Then it is up to the author of *i to overload assignment on rvalues (or not).
| container<sole_ptr<T>> is not copyable nor copy-assignable. | container<sole_ptr<T>> is movable. Thus sequences of | container<sole_ptr<T>> (container<container<sole_ptr<T>>>) can also be | operated on by move-aware in-place-mutating sequence algorithms. | | Elements of container<sole_ptr<T>> can't be copied into or out of the | container with copy syntax: | | sole_ptr<T> t = v[i]; // compile time error | | But elements can be moved into or out of the container: | | sole_ptr<T> t = move(v[i]); | v.push_back(move(t));
so move(v[i]) must also erase the element and then move the rest of the vector one place back?
Nope. move(v[i]) would move from the sole_ptr<T> at i, but not erase it. v[i] would now own nothing. This is another difference between this future language I'm describing, and the Smart Container Library. The former allows null pointers where the latter doesn't.
| This future move-aware | container<clone_ptr<T>> would not clone objects as it moved them around | internally, but would clone objects for the purpose of copying them | into or out of the container,
sounds expensive to me.
<nod> If clients wanted to, they could move clone_ptr<T> into and out of the container instead of copy it in and out. For rvalue clone_ptr<T>'s, this would happen automatically, but for lvalue clone_ptr<T> the client would have to explicitly request the move. E.g.: v.push_back(clone_ptr<base>(new derived)); // rvalue clone_ptr moved into v clone_ptr<base> p(new derived); v.push_back(p); // p copied/cloned into v v.push_back(move(p)); // p moved into v, p now null -Howard