简体   繁体   中英

Nesting std::containers of movable objects

I have a class NoCopy that is movable , but not copiable .

I need to make a vector of 3 queues of NoCopy . I can create an empty one, but there is no way to add any element.

I can make a std::vector<NoCopy> or std::queue<NoCopy> and populate them. But not for 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;
}

Any ideas?

By default, std::queue is based on std::deque , which is not guaranteed to be nothrow-movable . Neither is the other suitable standard container, std::list ; these rules allow implementations that always allocate at least one node/block. std::vector uses copies to reallocate when moving might throw (so as to guarantee exception safety) unless the type is not copyable at all, and those two containers also do not propagate non-copyability from their element type but just fail if you try. The last could be said to be a defect in the standard, since expectations for such propagation keep going up, but fixing it is incompatible with support for incomplete types:

struct Node {
  std::vector<Node> children;
  // …
};

Note that both libstdc++ and libc++ do make those two containers nothrow-movable (as of version 9 in each case), which is a permitted extension, but MSVC's STL does not.

You can still use std::vector<QNC> v(3); ; the constructor “knows” that re allocation is never necessary. Or you can provide a wrapper ( eg , a class derived from std::queue ) that is non-copyable or is nothrow-movable; the former will waive the exception safety of std::vector , while the latter will call std::terminate if moving the underlying container does throw.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM