Подтвердить что ты не робот

STL vector: перемещение всех элементов вектора

У меня есть два вектора 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.

4b9b3361

Ответ 1

Используя С++ 11, он прост как:

A = std::move(B);

Теперь A содержит элементы, ранее сохраненные B, а B теперь пуст. Это позволяет избежать копирования: внутреннее представление просто перемещается из B в A, поэтому это решение O(1).

Что касается С++ 03, то в качестве Prætorian вы можете поменять векторы. Существует специализация функции std::swap, которая принимает std::vector в качестве своих аргументов. Это эффективно меняет внутреннее представление, поэтому вы избегаете создания копий элементов, принадлежащих им. Эта функция работает и с O(1) сложностью.

Ответ 2

Если у вас есть компилятор С++ 11, вы можете переместить B в A.

A = std::move(B);

Если вы работаете со старым компилятором, просто swap два

A.swap(B);

В обоих случаях единственная операция O (N) будет очищать содержимое A. В первом случае очистка будет выполняться во время самого присваивания, а во втором это произойдет, когда B выходит за рамки (поскольку содержимое было заменено).

Ответ 3

У меня есть два вектора STL A и B, и я хотел бы очистить все элементы A и переместить все элементы B в A, а затем очистить B.

Это можно сделать с помощью комбинации swap. Первый обмен A и B для первой половины. Затем swap пустой std::vector<> с B или вызовите clear(). Разница в том, что 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);

Ответ 4

просто вызывать clear on vector будет принимать o (1) раз, поскольку clear ничего не сделает, Если вы действительно хотите очистить B после назначения A, вы можете сделать следующее

A.swap(B);
{
    std::Vector<..> C;
    c.swap(B);
}

Ответ 5

Функция swap делает это.

#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:

Ответ 6

Если вы не можете std:: move или std:: swap векторы (например, поскольку A и B связаны, но разные типы, возможно, отличаются только константой), вы можете сделать:

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

Обратите внимание, что это оставляет А с одинаковым количеством элементов, но все они находятся в неопределенном состоянии (т.е. они могут быть назначены или уничтожены, но не прочитаны).

Ответ 7

std :: move работает отлично. Вот пример кода для того же

    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

Ответ 8

Мне не хватает репутации, чтобы комментировать, но я хочу упомянуть, что согласно: https://en.cppreference.com/w/cpp/container/vector/operator%3D void.pointer правильно. Особенно...

2) Оператор присваивания перемещения. Заменяет содержимое другими, используя семантику перемещения (т.е. Данные в другом перемещаются из другого в этот контейнер). другой находится в допустимом, но неопределенном состоянии впоследствии.

Таким образом, преторианский ответ неверен для каждого стандарта. Однако, по крайней мере, для MSVC это достаточно хорошо, потому что реализация все равно очищает список (вероятно, верно для большинства).

Что интересно, так как мы объявляем конструктор перемещения, неявный оператор присваивания перемещения не будет объявлен. Таким образом, мы "знаем", что std :: vector должен объявить оператор присваивания перемещения.