Чтобы обеспечить семантику перемещения для вектора, мы должны сообщить C ++ (в частности, std :: vector ), что конструктор перемещения и деструктор не генерирует, используя noexcept
. Тогда конструктор перемещения будет вызываться при увеличении вектора. См. Это примечание:
Чтобы обеспечить гарантию строгих исключений, определяемые пользователем конструкторы перемещения не должны генерировать исключения. Например, std :: vector использует std :: move_if_noexcept для выбора между перемещением и копированием, когда необходимо переместить элементы.
Подробнее о том, что сказано в стандарте, читайте C ++ Переместить семантику и исключения
Если конструктор не noexcept , std :: vector не может использовать его, с тех пор он не может обеспечить гарантии исключений, требуемые стандартом.
В случае std :: map стандарт ничего не говорит о безопасности исключений для конструктора перемещения карты. Таким образом, компиляторы (в вашем случае, gcc
и clang
) могут помечать функции как не имеющие отношения к делу, независимо от того, предписывает ли это Стандарт или нет.
Об альтернативах или обходном пути см. Мой пример ниже (проверено с помощью gcc
):
#include <vector>
#include <map>
#include <memory>
void foo(void)
{
std::vector<std::vector<std::unique_ptr<int>>> outer;
std::vector<std::unique_ptr<int>> inner;
std::unique_ptr<int> p = std::make_unique<int>(1);
inner.emplace_back(std::move(p));
outer.emplace_back(std::move(inner));
}
void bar(void)
{
std::vector<std::pair<std::unique_ptr<int>, std::unique_ptr<int>>> vec;
std::unique_ptr<int> p1 = std::make_unique<int>(1);
std::unique_ptr<int> p2 = std::make_unique<int>(2);
auto pair = std::make_pair(std::move(p1), std::move(p2));
vec.emplace_back(std::move(pair));
}
void bar2(void)
{
std::vector<std::unique_ptr<std::map<std::unique_ptr<int>, std::unique_ptr<int>>>> vec;
std::unique_ptr<int> p1 = std::make_unique<int>(1);
std::unique_ptr<int> p2 = std::make_unique<int>(2);
auto map = std::make_unique<std::map<std::unique_ptr<int>, std::unique_ptr<int>>>();
map->emplace(std::move(p1), std::move(p2));
vec.emplace_back(std::move(map));
}
int main(int argc, char *argv[])
{
foo();
bar();
return 0;
}
БОНУС:
Используйте emplace_back , когда это возможно. Он может быть быстрее (но часто это не так), он может быть более четким и компактным, но есть и некоторые подводные камни (особенно с неявными конструкторами).