std::vector<std::queue<Buf>>调用resize编译报错的原因及解决
问题分析与解答
问题背景
给出Buf类定义:
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); } };
将其放入std::queue后编写主函数:
int main() { std::vector<std::queue<Buf>> data; data.resize(10); // 编译错误 return 0; }
调用resize(10)时触发编译错误,核心错误信息:
error: static assertion failed: result type must be constructible from value type of input range
改用std::deque<std::queue<Buf>>则可正常编译,以下是具体分析:
一、报错原因
Buf类显式删除了拷贝构造和拷贝赋值操作,仅保留默认构造、移动构造和移动赋值。std::queue<Buf>默认底层容器是std::deque<Buf>,由于Buf不可拷贝,std::deque<Buf>的拷贝构造/赋值操作被隐式删除,进而导致std::queue<Buf>的拷贝构造/赋值操作也被隐式删除。std::vector::resize在扩展容量时,部分编译器的实现会依赖元素的拷贝构造能力(例如内部内存分配算法需要拷贝已有元素或临时对象)。而std::queue<Buf>不可拷贝,因此触发静态断言错误。
二、解决办法
方法1:用emplace_back替代resize
直接在vector中构造空的std::queue<Buf>,避免依赖拷贝操作:
int main() { std::vector<std::queue<Buf>> data; data.reserve(10); // 预分配容量,减少扩容次数 for (int i = 0; i < 10; ++i) { data.emplace_back(); // 直接在vector内存中构造空队列 } return 0; }
方法2:实现Buf的拷贝构造(需注意内存安全)
如果业务允许拷贝Buf,可以实现深拷贝的拷贝构造函数,确保std::queue<Buf>具备拷贝能力:
// 在Buf类中添加拷贝构造函数 Buf(const Buf& other) { size = other.size; data = static_cast<uint8_t*>(malloc(size)); if (data && other.data) { memcpy(const_cast<uint8_t*>(data), other.data, size); } } // 同时恢复拷贝赋值操作(可选,按需实现) Buf& operator=(const Buf& other) { if (this != &other) { free(const_cast<void*>(static_cast<const void*>(data))); size = other.size; data = static_cast<uint8_t*>(malloc(size)); if (data && other.data) { memcpy(const_cast<uint8_t*>(data), other.data, size); } } return *this; }
三、std::deque可正常编译的原因
std::deque采用分段式内存布局,扩容时不需要重新分配整块内存,也不需要移动或拷贝已有的元素。- 调用
std::deque::resize(10)时,它会直接在新的内存段中默认构造10个std::queue<Buf>对象,仅要求元素可默认构造(std::queue<Buf>默认构造空队列,无需构造Buf实例),完全不依赖元素的拷贝/移动能力。 - 因此
std::deque的resize操作可以正常执行,不会触发编译错误。
内容的提问来源于stack exchange,提问作者ATK
相关产品推荐
相关产品推荐

