2011-11-23 133 views
20

如何在不将容器的所有权从容器中取出的情况下访问容器的unique_ptr元素(通过迭代器)?当一个迭代器获得容器中的元素时,容器的元素所有权仍然存在?如何取消引用迭代器以访问unique_ptr?这是否执行unique_ptr的隐式移动?迭代unique_ptr的容器

我发现我使用shared_ptr的很多时候我需要存储元素的容器(不是值),即使容器在概念上拥有的元素和其他代码只是希望操纵元素的容器,因为我害怕不能实际访问容器中的unique_ptr元素而没有从其中获取所有权。

任何见解?

回答

13

只要您不尝试复制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<unique_ptr<T>>已建成。事情应该正常工作,如果他们不这样做,问题就出现在编译时而不是运行时。所以,编码,如果你不明白编译时错误,然后再问这个问题。

+0

好的,我认为这说明了我的事情。我一直习惯于使用新的for_each函数,其lambda参数是通过值传递的元素,而不是通过引用,但是如果我想避免尝试,我想我必须为unique_ptr元素引用它复制/移动。附:如果我将迭代器解引用一次,然后参照该结果,我认为这样可以避免尝试复制?我的意思是: {for Container :: iterator it = container.begin(); it!= container.end(); it ++) { unique_ptr &element = &*it; //没有尝试复制? }' 谢谢霍华德,顺便说一句。 –

+0

是的,我认为这应该可以正常工作。尽管你的代码中有一个额外的'&'。但编译器会告诉你在哪里。 –

+0

你应该能够将它解引用到:blah&element = **它;我想,仍然没有副本。 (可能更有用) –

32

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

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

参考&std::unique_ptr避免了复制和可以使用uniqe_ptr而不解除引用。

+0

有没有人知道在这种情况下使用'auto&'和'auto &&'是否有区别?此参考文献建议双&http://en.cppreference.com/w/cpp/language/range-for,似乎都编译 – austinmarton

+0

好问题。我发现[这个链接](http://en.cppreference.com/w/cpp/language/auto)(见解释/ 1),它表明'auto &&'可能作为左值和右值取决于初始值设定项。我相应地调整了示例。 – Pascal