包装指针如何与rvalue引用一起使用?

时间:2013-04-10 05:15:39

标签: c++ c++11 operator-overloading rvalue-reference

std :: shared_ptr :: operator *通过左值引用返回,并且重载指针(如操作here)给出的答案表示约定是通过左值引用返回的。但是,当我使用以下代码时,我得到错误C2664:'AdjacencyList :: addVertex':无法将参数1从'AdjacencyList :: vertex_type'转换为'AdjacencyList :: vertex_type&&':您无法绑定左值参考的左值:

std::shared_ptr<vertex_type> AdjacencyList::addVertex(vertex_type&& v)
{
    auto existingVertex(findVertex(v));

    if (!existingVertex.isValid())
    {
        existingVertex = std::make_shared<vertex_type>(std::forward<vertex_type>(v))
        m_vertices.push_back(existingVertex);
    }

    return existingVertex;
};

AdjacencyList minimumSpanningTree;
// startVertex is a shared_ptr to a vertex returned from a previous call of addVertex
// on another AdjacencyList object
const auto mstStartVertex(minimumSpanningTree.addVertex(*startVertex));

我应该提供AdjacencyList :: addVertex(const vertex_type&amp; v)还是更改上面块底部的代码,以便在传递给addVertex之前复制顶点?

AdjacencyList minimumSpanningTree;
Vertex s(*startVertex);
const auto mstStartVertex(minimumSpanningTree.addVertex(std::move(s)));

2 个答案:

答案 0 :(得分:2)

我认为您应该从operator*返回副本,因为std::weak_ptr的语义表明您不能保证返回的引用保持有效。由于返回的副本随后被赋予可以将其移动到其他地方的函数,因此它也应该足够有效,因为addVertex看起来无论如何都需要副本,即,如果你创建addVertex的重载,它将在内部创建传递的const引用的副本,是吗?

答案 1 :(得分:1)

就冗余副本而言,最有效的方法是提供rvalue和const引用重载:

std::shared_ptr<vertex_type> AdjacencyList::addVertex(vertex_type&&);
std::shared_ptr<vertex_type> AdjacencyList::addVertex(const vertex_type&);

要消除冗余代码,您可以转发模板方法或采用bool标记并在适当时执行const_cast的具体方法。

如果复制Vertex对象的开销与增加代码的成本相比最小,并且通常或经常输入if块,则冗余副本将使您的代码更清晰。如果您只是创建一个不需要移动的prvalue临时值,那么您的第二个建议调用将会更好:

const auto mstStartVertex(minimumSpanningTree.addVertex(Vertex{*startVertex}));

但是在这种情况下,您也可以通过提供单个值重载(How to reduce redundant code when adding new c++0x rvalue reference operator overloads)来在调用本身中创建临时值:

std::shared_ptr<vertex_type> AdjacencyList::addVertex(vertex_type);