On Sunday, January 24, 2016 at 10:03:52 PM UTC+1, Paul wrote:
> Suppose we want to swap the first two elements of a vector<T>
> Suppose further that the type T is very large so we want to avoid
> copying.
What kind of size are we talking about? sizeof(T)? Or size in terms
of how costly copying would be? The sizeof() a vector is rather small
(just three pointers) but copying a vector might involve copying lots
of other things that are not *directly* part of the vector.
> Suppose v is a vector<T>
> We can do
> T temp = v[0]; v[0] = v[1]; v[1] = temp;
> However, this seems to involve unnecessary copying.
You should do
using std::swap; // fall back on std::swap
swap(v[0], v[1]); // might invoke another swap via ADL
instead because it might resolve to a special swap function that has
been optimized for the type T (via ADL or a specialized std::swap).
std::swap's default implementation also makes use of move semantics:
template<class T>
void swap(T& a, T& b) noexcept(...) {
T t = std::move(a); // tries to move a into t
a = std::move(b); // tries to move b into a
b = std::move(t); // tries to move t into b
}
which is obviously better if T has a move constructor and move
assignment operator that is more efficient that their respective
copy versions.
> I therefore suggested that, for an operation that involves a lot of
> swapping (for example, a sort), we should use a vector of pointers
> to T rather than a vector<T> and swap via the pointers.
Yeah, if sizeof(T) is huge, this indirection might help. I would also
suggest to test this approach (std::vector<unique_ptr<T>> or boost::
ptr_vector<T>). If your T is a vector or a string, for example, this
is however not the case.
> However, someone (in a private conversation so I don't want to name
> the person) told me that T temp = v[0]; v[0] = v[1]; v[1] = temp;
> does not in fact move large objects around, and only moves pointers,
> so that my issue doesn't really exist.
First of all, it does not move anything because you didn't ask for it.
That's what std::move is for.
T temp = v[0]; // this *copies* v[0] to temp
There are situations where std::move is not necessary and in those
situations using std::move is actually somewhat harmful (since it
disables the otherwise applicable copy elision optimizations) but this
is not one of them, so you need to use std::move here.
But then it also depends on what T is and goes back to my first
question. If T is something like a std::vector<U> then you *don't*
need this additional layer of indirection because a vector *already*
stores its "elements" indirectly and has very efficient move
operations. These move operations are doing the pointer
manipulations. If sizeof(T) is huge, this is another story.
Cheers!
sg