代码之家  ›  专栏  ›  技术社区  ›  aminfar

STL矢量:移动矢量的所有元素

  •  68
  • aminfar  · 技术社区  · 12 年前

    我有两个STL矢量 A B 我想清除 A. 并移动的所有元素 B A. 然后清除 B 。简单地说,我想这样做:

    std::vector<MyClass> A;
    std::vector<MyClass> B;
    ....
    A = B;
    B.clear();
    

    自从 B 可能很长,需要 k*O(N) 要执行此操作,其中 k 是一个常数,并且 N max(size_of(A), size_of(B)) 。我想知道是否有更有效的方法。我能想到的一件事是定义 A. B 作为指针,然后在恒定时间内复制指针并清除 B

    8 回复  |  直到 12 年前
        1
  •  129
  •   mfontanini    11 年前

    使用C++11,它非常简单:

    A = std::move(B);
    

    现在 A 包含以前由持有的元素 B B 现在是空的。这样可以避免复制:只需从 B A. ,所以这是一个 O(1) 解决方案

    至于C++03,正如普托里状态一样,你可以交换向量。有一个专门的 std::swap 函数,需要 std::vector s作为其论据。这有效地交换了内部表示,因此最终避免了创建它们所持有的元素的副本。此功能适用于 O(1) 复杂性也是如此。

        2
  •  20
  •   Praetorian Luchian Grigore    12 年前

    如果你有一个C++11编译器,你可以移动 B 进入 A

    A = std::move(B);
    

    如果您使用的是较旧的编译器,只需 swap 二者

    A.swap(B);
    

    在这两种情况下 O(N) 操作将清除 A. .在第一种情况下,清算将在转让期间进行,而在第二种情况下将在 B 超出范围(因为内容已交换)。

        3
  •  6
  •   Sameer Ahuja    6 年前

    std:移动效果很好。以下是相同的示例代码

        vector<int> v1 = {1,2,3,10,20,30,100,200,300,999};
        vector<int> v2;
    
        cout << "Size of v1 before move = " << v1.size() << endl;
        cout << "Capacity of v1 before move = " << v1.capacity() << endl;
    
        v2 = std::move(v1);
    
        cout << "Size of v2 after move = " << v2.size() << endl;
        cout << "Capacity of v2 after move = " << v2.capacity() << endl;
    
        cout << "Size of v1 after move = " << v1.size() << endl;
        cout << "Capacity of v1 after move = " << v1.capacity() << endl;
    
    -----------Output-------------------------
    Size of v1 before move = 10
    Capacity of v1 before move = 10
    Size of v2 after move = 10
    Capacity of v2 after move = 10
    Size of v1 after move = 0
    Capacity of v1 after move = 0
    
        4
  •  5
  •   David Rodríguez - dribeas    12 年前

    我有两个STL向量A和B,我想清除A的所有元素,将B的所有元素移动到A,然后清除B。

    这可以通过以下组合来完成 swap .首次掉期 A B 上半场。然后 交换 空的 std::vector<> 具有 B 或呼叫 clear() 不同之处在于 清除() 不会释放内存,只会破坏对象:

    std::vector<int> a, b; // initialize them somehow
    swap(a,b);
    
    // clear b without releasing the memory:
    std::size_t capacity = b.capacity();
    b.clear();
    assert(b.capacity()==capacity);
    
    // or release the memory
    std::vector<int>().swap(b);
    assert(b.capacity()==0);
    
        5
  •  4
  •   mogulkahn    12 年前

    只需在向量上调用clear就需要o(1)时间,因为clear什么都不做, 如果您真的想在将B分配给A后清除它,您可以执行以下操作

    A.swap(B);
    {
        std::Vector<..> C;
        c.swap(B);
    }
    
        6
  •  2
  •   Jason    12 年前

    交换功能可以做到这一点。

    #include <iostream>
    #include <iterator>
    #include <vector>
    
    int main(int argc, char* argv)
    {
      std::vector<int> A;
      std::vector<int> B;
    
      for (int i = 0; i < 10; ++i)
      {
         B.push_back(i);
      }
    
      std::cout << "Before swap\n";
      std::cout << "A:";
      std::copy(A.begin(), A.end(), std::ostream_iterator<int>(std::cout, " "));
      std::cout << "\nB:";
      std::copy(B.begin(), B.end(), std::ostream_iterator<int>(std::cout, " "));
      std::cout << "\n";
    
      A.swap(B);
      B.clear();
    
      std::cout << "After swap\n";
      std::cout << "A:";
      std::copy(A.begin(), A.end(), std::ostream_iterator<int>(std::cout, " "));
      std::cout << "\nB:";
      std::copy(B.begin(), B.end(), std::ostream_iterator<int>(std::cout, " "));
      std::cout << "\n";
    }
    

    输出

    Before swap
    A:
    B:0 1 2 3 4 5 6 7 8 9 
    After swap
    A:0 1 2 3 4 5 6 7 8 9 
    B:
    
        7
  •  2
  •   metal    8 年前

    如果不能std::move或std::swap向量(例如,因为A和B是相关的,但类型不同,可能只相差const),则可以执行以下操作:

    std::vector<MyClass>       A;
    std::vector<const MyClass> B;
    // ...
    for( auto& a : A )
    {
        B.emplace_back( std::move( a ) );
    }
    

    请注意,这使A具有相同数量的元素,但它们都处于不确定状态(即,它们可以被分配或销毁,但不能被读取)。

        8
  •  2
  •   redfeatherplusplus    6 年前

    我没有代表发表评论,但我想根据以下内容提及: https://en.cppreference.com/w/cpp/container/vector/operator%3D 无效。指针是对的。特别是。。。

    2) 移动分配运算符。使用移动语义将内容替换为其他容器的内容(即其他容器中的数据从其他容器移动到此容器中)。另一个在之后处于有效但未指定的状态。

    因此,按照标准,总督的回答是错误的。然而,至少对MSVC来说,这已经足够好了,因为该实现无论如何都会清除列表(对大多数人来说可能是真的)。

    有趣的是,由于我们声明了一个移动构造函数,因此不会声明任何隐式的移动赋值运算符。因此,我们“知道”std::vector必须声明一个移动赋值运算符。