C ++ 11 STL容器,支持仅移动类型,对开头和结尾具有O(1)写访问权限

时间:2016-12-06 15:54:36

标签: c++ performance c++11 stl containers

我正在开发一个应用程序,我需要排队某些仅限移动类型,我需要快速写入访问权限 开头和容器的结束(主要是快速添加元素)。

乍一看我想使用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中。

1 个答案:

答案 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中;然而,这是一个例子“如果它在您的编译器中有效,请使用它,因为未来的编译器将支持它”。