从类方法C ++ 0x返回unique_ptr

时间:2010-09-23 10:43:44

标签: c++ c++11 smart-pointers unique-ptr

如果我的类SomeType有一个从地图返回元素的方法(使用键),请说

std::unique_ptr<OtherType> get_othertype(std::string name)
{
   return otMap.find(name);
}

这会确保调用者会收到指向地图中指针而不是副本的指针吗?这样做是否可以,或者它会尝试调用复制构造函数(并因为它被删除而失败),因为它正在被返回?

假设我必须使用unique_ptr作为我的地图项目。

UPDATE ::

在尝试实现代码之后,似乎unique_ptr和std:map /:pair在gcc 4.4.4中不能一起工作,只是不喜欢unique_ptr作为类型参数。 (见Can't create map of MoveConstructibles)。

我将ptr更改为std :: shared_ptr并且一切正常。

我想我可以在共享指针上使用相同的代码吗?

4 个答案:

答案 0 :(得分:12)

unique_ptr的模型是所有权转移。如果从函数返回unique_ptr对象,则系统中没有其他unique_ptr可能引用同一对象。

这就是你想要的吗?我非常怀疑它。当然,你可以简单地返回一个原始指针:

OtherType* get_othertype(const std::string& name)
{
    return otMap.find(name)->second.get();
}

因此,客户端可以访问该对象,但地图仍然拥有它。

如果在名称下没有找到条目,上述解决方案相当脆弱。更好的解决方案是在这种情况下抛出异常或返回空指针:

#include <stdexcept>

OtherType* get_othertype(const std::string& name)
{
    auto it = otMap.find(name);
    if (it == otMap.end()) throw std::invalid_argument("entry not found");
    return it->second.get();
}

OtherType* get_othertype(const std::string& name)
{
    auto it = otMap.find(name);
    return (it == otMap.end()) ? 0 : it->second.get();
}

为了完整起见,这是Anthony提出的返回引用的建议:

OtherType& get_othertype(const std::string& name)
{
    auto it = otMap.find(name);
    if (it == otMap.end()) throw std::invalid_argument("entry not found");
    return *(it->second);
}

以下是如何在地图中返回对unique_ptr的引用,但是让我们对const进行引用,这样客户端就不会意外地修改原始内容:

unique_ptr<OtherType> const& get_othertype(const std::string& name)
{
    auto it = otMap.find(name);
    if (it == otMap.end()) throw std::invalid_argument("entry not found");
    return it->second;
}

答案 1 :(得分:2)

otMap的类型是什么?

如果otMap.find(name)返回std::unique_ptr<OtherType>作为右值,那么这将正常工作。但是,指向值的所有权现在已转移到返回的指针,因此该值将不再位于映射中。这意味着您使用的是自定义地图类型而不是std::map<>

如果你希望能够在地图中返回一个指向它的指针,那么你需要使用std::shared_ptr<OtherType>作为地图值类型和返回类型get_othertype()

std::map<std::string,std::shared_ptr<OtherType>> otMap;
std::shared_ptr<OtherType> get_othertype(std::string name)
{
    auto found=otMap.find(name);
    if(found!=otMap.end())
        return found->second;
    return std::shared_ptr<OtherType>();
}

答案 2 :(得分:0)

otMap.find将返回一个右值,因此如果不是RVO,则会移动该右值。但是,当然,现在你的地图中没有那个特定的对象。另外,我上次检查时,find返回一个迭代器,而不是值类型。

答案 3 :(得分:0)

您是否考虑更改地图以暂停shared_ptr而不是unique_ptr?这将使返回值更安全。 unique_ptr的重点是它是唯一的(即共享)。