【问题标题】:Iterating over a container of unique_ptr's遍历 unique_ptr 的容器
【发布时间】:2011-11-23 04:51:52
【问题描述】:

如何访问容器的 unique_ptr 元素(通过迭代器)而不剥夺容器的所有权?当一个人获得容器中元素的迭代器时,元素所有权仍然在容器中吗?当一个人取消对迭代器的引用以获取对 unique_ptr 的访问权时怎么样?这会执行 unique_ptr 的隐式移动吗?

我发现当我需要在容器中存储元素(而不是按值)时,我经常使用 shared_ptr,即使容器在概念上拥有元素并且其他代码只是希望操纵容器中的元素,因为我'我害怕在没有所有权的情况下无法实际访问容器中的 unique_ptr 元素。

有什么见解吗?

【问题讨论】:

    标签: c++ iterator containers unique-ptr


    【解决方案1】:

    使用 auto 和 C++11 的基于范围的 for 循环,这变得相对优雅:

    std::vector< std::unique_ptr< YourClass >> pointers;
    for( auto&& pointer : pointers ) {
        pointer->functionOfYourClass();
    }
    

    std::unique_ptr 的引用&amp; 避免了复制,您可以使用uniqe_ptr 而无需取消引用。

    【讨论】:

    • 有谁知道在这种情况下使用auto &amp;auto &amp;&amp; 是否有区别?该参考表明 double & en.cppreference.com/w/cpp/language/range-for 似乎都可以编译
    • 好问题。我发现this link(参见解释/1)表明auto&amp;&amp; 可以作为左值和右值工作,具体取决于初始化程序。我相应地调整了这个例子。
    • 难道const auto &amp; 效果最好?
    • @JanHošek:这显然取决于你想做什么。在这个问题中,没有任何地方说明该对象没有被函数修改。如果可以,请使用 const。
    【解决方案2】:

    只要您不尝试复制unique_ptr,您就可以使用它。您必须“双重取消引用”迭代器才能获得指针的值,就像您必须使用 shared_ptr 一样。这是一个简短的例子:

    #include <vector>
    #include <memory>
    #include <iostream>
    
    template <class C>
    void
    display(const C& c)
    {
        std::cout << '{';
        if (!c.empty())
            std::cout << *c.front();
        for (auto i = std::next(c.begin()); i != c.end(); ++i)
            std::cout << ", " << **i;
        std::cout << "}\n";
    }
    
    int main()
    {
        typedef std::unique_ptr<int> Ptr;
        std::vector<Ptr> v;
        for (int i = 1; i <= 5; ++i)
            v.push_back(Ptr(new int(i)));
        display(v);
        for (auto i = v.begin(); i != v.end(); ++i)
            **i += 2;
        display(v);
    }
    

    如果您(不小心)复制了unique_ptr

    Ptr p = v[0];
    

    然后你会在编译时发现。它不会导致运行时错误。您的用例就是构建container&lt;unique_ptr&lt;T&gt;&gt; 的原因。事情应该可以正常工作,如果没有,问题就会出现在编译时而不是运行时。所以代码走开,如果你不理解编译时错误,那么在这里再问一个问题。

    【讨论】:

    • 好的,我认为这对我来说很清楚。我一直习惯于将新的 for_each 函数与 lambda 一起使用,其参数是按值传递的元素,而不是按引用传递的元素,但我想如果我想避免尝试,我必须将其作为 unique_ptr 元素的引用复制/移动。附言如果我取消引用迭代器一次,并引用该结果,我认为这避免了尝试复制?我的意思是:for(Container::iterator it = container.begin(); it != container.end(); it++) { unique_ptr&lt;blah&gt;&amp; element = &amp;*it; // No attempted copy? } 谢谢霍华德,顺便说一句。
    • 是的,我认为应该可以正常工作。尽管您的代码中有一个额外的&amp;。但是编译器会告诉你在哪里。
    • 您应该能够将其取消引用为: blah& element = **it;我认为仍然没有副本。 (可能更有用。)
    猜你喜欢
    • 2014-03-07
    • 1970-01-01
    • 2010-10-04
    • 2013-12-16
    • 2019-07-18
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 2013-11-04
    相关资源
    最近更新 更多