Вложенность std :: контейнеры с подвижными объектами - PullRequest
4 голосов
/ 17 апреля 2020

У меня есть класс NoCopy, который подвижен , но не копируется .

Мне нужно сделать вектор из 3 очередей NoCopy. Я могу создать пустой, но нет никакого способа добавить какой-либо элемент.

Я могу сделать std::vector<NoCopy> или std::queue<NoCopy> и заполнить их. Но не для std::vector<std::queue<NoCopy>>.

MWE:

#include <iostream>
#include <vector>
#include <queue>

class NoCopy{
public:
    NoCopy() = default;
    NoCopy& operator = (const NoCopy&) = delete;
    NoCopy(const NoCopy&) = delete;

    NoCopy(NoCopy&&) = default;
    NoCopy& operator = (NoCopy&&) = default;

};
using QNC = std::queue<NoCopy>;

int main(void) {
    QNC q;
    q.push(std::move(NoCopy()));

    std::vector<NoCopy> ncvec;
    ncvec.emplace_back();

    std::cout << "Queue size " << q.size() << ", vector size: " << ncvec.size() << std::endl;

    std::vector<QNC> qvec;
    //????

    return 0;
}

Есть идеи?

1 Ответ

2 голосов
/ 17 апреля 2020

По умолчанию std::queue основан на std::deque, который не гарантируется как nothrow-movable . Ни один другой подходящий стандартный контейнер, std::list; эти правила допускают реализации, которые всегда выделяют как минимум один узел / блок. std::vector использует копии для перераспределения, когда перемещение может выдать (чтобы гарантировать безопасность исключений), если тип не копируется вообще, и эти два контейнера также не распространяют не копируемость из своего типа элемента, но просто потерпите неудачу, если попытаетесь. (Можно сказать, что последнее является дефектом в стандарте; ожидания такого распространения продолжают расти.)

Обратите внимание, что и libstdc ++, и libc ++ do делают эти два контейнера не перемещаемыми ( начиная с версии 9 в каждом случае), что является допустимым расширением, но STL MSVC этого не делает.

Вы по-прежнему можете использовать std::vector<QNC> v(3);; конструктор «знает», что re распределение никогда не требуется. Или вы можете предоставить оболочку ( например , класс, производный от std::queue), который не копируется или не может быть перемещен; первый исключит безопасность исключений std::vector, а второй вызовет std::terminate, если перемещение базового контейнера вызывает throw.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...