How to use c++11 move semantics to append vector contents to another vector?
请考虑以下代码段:
1 2 3 4 5 6 7 | class X; void MoveAppend(vector<X>& src, vector<X>& dst) { dst.reserve(dst.size() + src.size()); for (const X& x : src) dst.push_back(x); src.clear(); } |
如果我们假设
Just do:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <iterator> #include // ... 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(); } } |
如果
如果
我会选择这一公认的好的答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <vector> #include <iterator> #include <utility> template <typename T> typename std::vector<T>::iterator append(const std::vector<T>& src, std::vector<T>& dest) { typename std::vector<T>::iterator result; if (dest.empty()) { dest = src; result = std::begin(dest); } else { result = dest.insert(std::end(dest), std::cbegin(src), std::cend(src)); } return result; } template <typename T> typename std::vector<T>::iterator append(std::vector<T>&& src, std::vector<T>& dest) { typename std::vector<T>::iterator result; if (dest.empty()) { dest = std::move(src); result = std::begin(dest); } else { result = dest.insert(std::end(dest), std::make_move_iterator(std::begin(src)), std::make_move_iterator(std::end(src))); } src.clear(); src.shrink_to_fit(); return result; } |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <string> #include #include <iostream> int main() { const std::vector<std::string> v1 {"world","!"}; std::vector<std::string> v2 {" <div class="suo-content">[collapse title=""]<ul><li>我认为这是一个更好的答案,有lvalue和rvalue源的重载,并使用std::vector::insert()。</li><li>为什么要"清除"右值源?我认为那是在做未经请求的额外工作。</li><li>@这是一个有趣的观点——我的观点是,调用方希望在调用后右值源的容量为零,否则情况就不是这样了。</li><li>@DanielCaller不应该期望任何关于移动对象状态的信息。移动的物体被认为是无效的,不应以任何方式使用。</li><li>这个函数不应该有两个版本。源应按值传递,而不是按const-ref或rvvalue传递。如果通过值传递源,调用方可以决定移动还是复制。</li><li>@格里塞夫:不过,这是附近的。正如调试中的vs如何用<wyn>0xDEADBEEF</wyn>之类的东西填充未初始化的内存(其内容在技术上是未指定和不可靠的),以帮助程序员进行调试。在这种情况下,即使是发布版本,也没有多少额外的工作……尽管我承认这可能比我们想要的要多,因为它仍然是n个析构函数调用。</li></ul>[/collapse]</div><p><center>[wp_ad_camp_1]</center></p><hr> <p> Just trying to improve slightly the answer of @Daniel: the function should not be defined twice, the source should be passed by value. </p> [cc lang="cpp"]// std::vector<T>&& src - src MUST be an rvalue reference // std::vector<T> src - src MUST NOT, but MAY be an rvalue reference template <typename T> inline void append(std::vector<T> source, std::vector<T>& destination) { if (destination.empty()) destination = std::move(source); else destination.insert(std::end(destination), std::make_move_iterator(std::begin(source)), std::make_move_iterator(std::end(source))); } |
现在可以决定是否对来电显示复制或移动。
1 2 3 4 | std::vector<int> source {1,2,3,4,5}; std::vector<int> destination {0}; auto v1 = append<int>(source,destination); // copied once auto v2 = append<int>(std::move(source),destination); // copied 0 times!! |
不使用