我正在开发一个应用程序,我需要排队某些仅限移动类型,我需要快速写入访问权限 开头和容器的结束(主要是快速添加元素)。
乍一看我想使用std::deque<T>
,但它要求T
是可复制构造的,因此它无法完成任务。
我现在正在考虑std::vector
,但我担心在vector
的开头添加元素会因为重新分配所有内容而变得非常慢。
有关此类容器的任何建议吗?
关于我需要的操作的注意事项(在std::deque
上):
emplace_back
emplace_front
pop_front
empty
front
这些是当前使用的操作(我的实现现在使用std::shared_ptr
使只移动类型可复制)
我需要排队的确切类型是std::function<void()>
的仅移动版本。如果我尝试使用std::deque
的仅移动版本,我会收到以下编译器错误(clang ++):
错误:使用已删除的函数'std :: packaged_task&lt; _Res(_ArgTypes ...)&gt; :: packaged_task(const std :: packaged_task&lt; _Res(_ArgTypes ...)&gt;&amp;) [_Res = void; _ArgTypes = {}]'包含在的文件中 /home/superuser/Desktop/thread_pool/thread_pool.hpp:32:0, 来自/home/superuser/Desktop/thread_pool/test.cpp:1:/ usr / include / c ++ / 6 / future:1513:7:注意:在这里声明 packaged_task(const packaged_task&amp;)= delete;
请注意,您看到std::packaged_task
,因为它被移动到由std::function<void()>
包裹的lambda中。
答案 0 :(得分:3)
这是[MCVE]如此有用的经典例子。
std::function<void()> fun = std::move(queue.front());
以上内容不会使用queue
中的不可复制内容进行编译。但是queue
工作正常。 std::deque
解决了您的问题。
std::function
要求其内容可以复制。即使你从未移动它,它也需要它是可复制的。 std::function
使用类型擦除,因此当您在其中存储内容时,将存储“如何复制”内容。
Here是一个仅限移动的std::function
,它不执行我在两年前写的小缓冲区优化。
今天我会用不同的方式写。我会从存储中拆分类型擦除,并编写一个单独的SBO存储类型,然后将它们连接在一起写入task<Sig>
。
有趣的是,packaged_task<void(Args...)>
是packaged_task<R(Args...)>
的类型已擦除SBO仅移动包装器。但它做得更多,所以我会避免使用它。
现在,std容器关于其内容要求的规则各不相同,标准经常变得更加自由。在某一点上,即使没有使用,也会将各种要求放在类型上;当前的标准规定这些要求是基于每个方法的。许多编译器在标准移动之前强制执行那些更自由的要求(因为几乎没有必要严格,标准没有要求它),所以即使在自由化之前的编译器中它也不是问题。我不确定这种自由化是否发生在C ++ 11的std::deque
中;然而,这是一个例子“如果它在您的编译器中有效,请使用它,因为未来的编译器将支持它”。