关于c ++:如何使用c ++ 11移动语义将向量内容附加到另一个向量?

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();
}

如果我们假设class X实现了移动语义,那么如何有效地实现MoveAppend


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();
    }
}

如果dst是空的,从A移动到dst赋值src想做的工作将是廉价的,因为它可以"偷"数组,只是想通过这样dstsrc包裹它后来点。

如果dst不是空的,一个元素appended dst将移动从src构造元素。std::move()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!!

不使用&&for论点,除非你有一个(例如:性病::ifstream &;&;)。