У меня есть два вектора 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
,
Используя C ++ 11, это так просто, как:
A = std::move(B);
Сейчас A
содержит элементы, которые были ранее проведены B
, а также B
сейчас пусто. Это позволяет избежать копирования: внутреннее представление просто перемещается из B
в A
так что это O(1)
решение.
Что касается C ++ 03, как утверждает Пруториан, вы можете поменять местами векторы. Существует специализация std::swap
функция, которая принимает std::vector
в качестве аргументов. Это эффективно меняет внутреннее представление, так что вы в конечном итоге избегаете создания копий содержащихся в них элементов. Эта функция работает в O(1)
сложность тоже.
Если у вас есть компилятор C ++ 11, вы можете переместить B
в A
,
A = std::move(B);
Если вы работаете со старым компилятором, просто swap
два
A.swap(B);
В обоих случаях единственным НА) операция будет очищать содержимое A
, В первом случае очистка будет выполняться во время самого присвоения, а во втором — когда B
выходит за рамки (так как содержимое было поменяно местами).
У меня есть два вектора 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);
просто вызов clear на vector займет o (1) время, так как clear ничего не сделает,
Если вы действительно хотите очистить B после назначения A, вы можете сделать следующее
A.swap(B);
{
std::Vector<..> C;
c.swap(B);
}
Функция свопа делает это.
#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:
Если вы не можете использовать 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 ) );
}
Обратите внимание, что это оставляет А с одинаковым количеством элементов, но все они находятся в неопределенном состоянии (то есть они могут быть назначены или уничтожены, но не считаны).
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
Мне не хватает репутации, чтобы комментировать, но я хочу упомянуть, что в: https://en.cppreference.com/w/cpp/container/vector/operator%3D void.pointer правильно. Особенно…
2) Оператор присваивания перемещения. Заменяет содержимое другими, используя семантику перемещения (т.е. данные в другом перемещаются из другого в этот контейнер). другой находится в допустимом, но неопределенном состоянии впоследствии.
Таким образом, преторианский ответ неверен для каждого стандарта. Однако, по крайней мере, для MSVC это достаточно хорошо, потому что реализация все равно очищает список (вероятно, верно для большинства).
Что интересно, так как мы объявляем конструктор перемещения, неявный оператор присваивания перемещения не будет объявлен. Таким образом, мы «знаем», что std :: vector должен объявить оператор присваивания перемещения.