Just do:
#include <iterator>
#include <algorithm>
// ...
void MoveAppend(std::vector<X>& src, std::vector<X>& dst)
{
if (dst.empty())
{
dst = std::move(src);
}
else
{
dst.reserve(dst.size() + src.size());
std::move(std::begin(src), std::end(src), std::back_inserter(dst));
src.clear();
}
}
If dst is empty, a move-assignment from src to dst will do the job – that will be as cheap as it can be, just “stealing” the array encapsulated by src so that dst will point to it afterwards.
If dst is not empty, elements appended to dst will be move-constructed from elements in src. After the call to std::move(), src will not be empty – it will contain “zombie” moved-from elements. That’s why the call to clear() is still necessary.