【问题标题】:How to get a move-only type out of a STL container?如何从 STL 容器中获取仅移动类型?
【发布时间】:2016-10-01 18:56:21
【问题描述】:

让我们以std::unique_ptr<T> 中的std::unordered_set 为例。我可以将集合中的一个元素移到其他地方吗?

#include <unordered_set>
#include <iostream>
#include <memory>
#include <vector>

int main()
{
    std::unordered_set<std::unique_ptr<int>> mySet;

    mySet.insert(std::make_unique<int>(1));
    mySet.insert(std::make_unique<int>(2));
    mySet.insert(std::make_unique<int>(3));

    std::vector<std::unique_ptr<int>> myVector;

    for (auto&& element : mySet)
    {
        std::cout << *element << std::endl;
        //myVector.push_back(element); won't compile as you can only get a const ref to the key
    }
}

我有一个非常实用的代码示例,我想在其中执行此操作,但减少到使用std::shared_ptr。您知道另一种(更好的?)替代方案吗?

【问题讨论】:

  • 请注意,如果mySetstd::vector,则不会出现此问题;这是node-based containers 特有的。另请注意,如果您成功移动它,它可能会对该设置的未定义行为进行其他操作,因为移动的对象不再有效读取,例如插入或查找,因此在使用容器时必须小心完全没有。
  • @metal 我可能做错了什么,但我只对向量有相同的编译错误,请参阅:coliru.stacked-crooked.com/a/51af3ac220c44619。编辑:我的错,使用std::move。谢谢 !新代码:coliru.stacked-crooked.com/a/95cb8a827d587723
  • here 描述了一种有用的技术,虽然丑陋但很有效。该代码用于擦除,但可以修改为移动/提取。

标签: c++ c++11 memory containers move


【解决方案1】:

在 C++03、C++11 和 C++14 中,不是直接使用。您必须将类型更改为:

template <class T>
struct handle {
    mutable std::unique_ptr<T> owning_ptr;
    T* observing_ptr; // enforce that observing_ptr == owning_ptr.get() on construction

    // define operator<, hash, etc. in terms of the observing ptr
};

有了这个,你可以写:

std::unordered_set<handle<int>> mySet;
// initialize as appropriate

for (auto& elem : mySet) {
    myVector.push_back(std::move(elem.owning_ptr));        
}
mySet.clear();

这仍然是明确定义的行为,因为我们不会弄乱任何容器内部 - 观察指针在 clear() 结束之前仍然有效,只是现在 myVector 拥有它。


在 C++17 中,我们可以在 extract() 的帮助下直接更简单地做到这一点:

for (auto it = mySet.begin(); it != mySet.end();  
{
    std::cout << **it << std::endl;
    myVector.push_back(std::move(
        mySet.extract(it++).value()));
}

【讨论】:

  • 您可以使容器包含一个可变标记的类似联合的智能指针和一个同意排序的哑指针,以及在返回智能时从智能切换到哑的操作。提取聪明人,消灭愚蠢人,鲍勃就是你的叔叔。
  • @Yakk 比你领先一步 :) 除了让它不是一个工会,但它可能是。
  • 不应该是handle&lt;int&gt; 而不是handle&lt;std::unique_ptr&lt;int&gt;&gt;
  • @Yakk 和@Barry 谢谢,我想我会去这个方便的handle 作为一个工会! ;)
  • 一对或结构类似于联合。 ;) 您还可以使用带有特殊删除器的唯一 ptr,该删除器将移动到默认删除理解为“转换为哑指针”。
猜你喜欢
  • 1970-01-01
  • 2012-09-05
  • 2011-03-02
  • 1970-01-01
  • 2017-12-15
  • 2012-02-16
  • 2017-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多