C++ STL 使用 vector<SafeList> 调整大小失败

问题描述

我定义了一个 ThreadSafe 列表,我想清除一个向量以保存一些 ThreadSafe 列表,但是当我使用 resize 初始化向量时,出现了一些错误

我定义的安全列表:

template<class T>
class SafeQueue{
public:
    SafeQueue() {}
    SafeQueue(const SafeQueue & sq) = delete;
    SafeQueue & operator = (const SafeQueue & sq) = delete;

private:
    std::queue<T> queue_;
    std::mutex mutex_;

初始化代码为:

for (auto & p : timer_) {
    // p type: std::vector<SafeContainer::SafeList<TimerNodePtr> >
    p.resize(SHIFT);
}

错误信息如下:

/usr/include/c++/9/bits/stl_uninitialized.h: In instantiation of ‘_ForwardIterator std::uninitialized_copy(_InputIterator,_InputIterator,_ForwardIterator) [with _InputIterator = std::move_iterator<SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> >*>; _ForwardIterator = SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> >*]’:
/usr/include/c++/9/bits/stl_uninitialized.h:307:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator,_ForwardIterator,std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> >*>; _ForwardIterator = SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> >*; _Tp = SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> >]’
/usr/include/c++/9/bits/stl_uninitialized.h:329:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator,_Allocator&) [with _InputIterator = SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> >*; _ForwardIterator = SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> >*; _Allocator = std::allocator<SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> > >]’
/usr/include/c++/9/bits/vector.tcc:659:48:   required from ‘void std::vector<_Tp,_Alloc>::_M_default_append(std::vector<_Tp,_Alloc>::size_type) [with _Tp = SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> >; _Alloc = std::allocator<SafeContainer::SafeList<std::shared_ptr<Timer::TimerNode> > >; std::vector<_Tp,_Alloc>::size_type = long unsigned int]’
/usr/include/c++/9/bits/stl_vector.h:937:4:   required from ‘void std::vector<_Tp,_Alloc>::resize(std::vector<_Tp,_Alloc>::size_type = long unsigned int]’
/home/ctrlz/workSpace/MyServer/src/Timer.cpp:8:23:   required from here
/usr/include/c++/9/bits/stl_uninitialized.h:127:72: error: static assertion Failed: result type must be constructible from value type of input range
  127 |       static_assert(is_constructible<_ValueType2,decltype(*__first)>::value,

有人可以帮我吗?谢谢!


最小可重现示例如下:

#include <vector>
#include <queue>
#include <mutex>
template<class T>
class SafeQueue{
public:
    SafeQueue() {}
    SafeQueue(const SafeQueue & sq) = delete;
    SafeQueue & operator = (const SafeQueue & sq) = delete;


private:
    std::queue<T> queue_;
    std::mutex mutex_;
};

int main() {
    std::vector<SafeQueue<int> > list;
    list.resize(5);
}

解决方法

您正在调用的 std::vector::resize 的重载要求元素为 MoveInsertableDefaultInsertable。使用默认分配器 MoveInsertable 有效地要求元素可移动构造,但您的 SafeQueue 不是。此断言失败:

static_assert( std::is_move_constructible_v<SafeQueue<int>> );

请看这里:https://godbolt.org/z/1c16zbzv8

事实上,对于不可复制、不可分配和不可移动元素的向量,您无能为力。假设您可以调整大小,但是您将无法分配给元素。重新分配还需要移动元素。