Home > Software design >  When resizing a std::vector of std::queue. Compile error; static assertion failed: result type must
When resizing a std::vector of std::queue. Compile error; static assertion failed: result type must

Time:10-24

I got the following class:

class  Buf  {
    const uint8_t *data;
    size_t size;
public:
    Buf() : data(nullptr), size(0) {};
    Buf(const uint8_t *data_, size_t size_) : data(data_), size(size_) { };
    Buf(Buf&& other) noexcept
        : data{std::exchange(other.data, nullptr)}, size{other.size} {};

    Buf& operator=(Buf&& other) noexcept {
        data = std::exchange(other.data, nullptr);
        size = other.size;
        return *this;
    }
    Buf(const Buf& other) = delete;
    Buf& operator=(Buf other) = delete;


    ~Buf()
    {
        free((void *)data);
    }
};

I use this class inside a queue

int main()
{
    std::vector<std::queue<Buf>> data;
    data.resize(10); // compile error
    return 0;
}

I get a long compile error boiling down to:

error: static assertion failed: result type must be constructible from value type of input range

If I in turn use a std::deque instead it seems to compile.

So why does not work with std::queue and how could it be fixed. And why does it seem to work with std::deque

The code: https://godbolt.org/z/Ev86YG1nG

CodePudding user response:

std::queue is a container adapter; that is, it forwards all of its actual operations to an internal container of a type specified by a template argument. By defualt, this container is std::deque.

However, std::deque<T> is not noexcept moveable. Therefore, when vector<T> attempts to resize itself, it cannot use the move operation; it must copy it. And since Buf is not copyable, neither is std::deque<Buf>. So vector tries to copy a non-copyable type; hence the compile error.

There's not really a good solution to this. vector is not a good type for a queue, since insertion/removal at the front is slow. And deque is not noexcept moveable, nor is list. Maybe if the queues are small, using std::queue<Buf, std::vector<Buf> might work out performance-wise.

Using std::deque for the outer container works because many of its operations do not require the type to be moveable or copyable. Insertion/removal from the head/tail don't provoke copying.

  • Related