C++ 如何返回引用或复制

C++ 如何返回引用或复制,c++,reference,C++,Reference,我有以下代码: EdgeSet Graph::GetNodeOutcomingEdges(long long NodeId) { //NodeEdgeMap is an unordereded_map NodeEdgeMap::iterator it = NodeOutcomingEdges.find(NodeId); if (it != NodeOutcomingEdges.end()) { return *(*(it)).second; }

我有以下代码:

EdgeSet Graph::GetNodeOutcomingEdges(long long NodeId) {
    //NodeEdgeMap is an unordereded_map
    NodeEdgeMap::iterator it = NodeOutcomingEdges.find(NodeId);
    if (it != NodeOutcomingEdges.end()) {
        return *(*(it)).second;
    }
    return EdgeSet();
}
然后

EdgeSet& OutcomingEdges = RoadGraph.GetNodeOutcomingEdges(Expandee.GetId());

因为该值不必在映射中,所以我必须以某种方式对其进行解释,在理想情况下,返回一个空的新EdgeSet。我可以抛出和异常,但有必要吗?这在VS下可以很好地编译,可能已经解释了RVO,但在g++中就不行了。

假设您确实想要返回一个引用,为了允许调用方修改返回的对象,您可以返回一个指向找到的对象的指针,如果找不到,则返回一个空指针:

NodeEdgeMap::iterator Graph::GetNodeOutcomingEdges(long long NodeId) {
    return NodeOutcomingEdges.find(NodeId);
}
EdgeSet* Graph::GetNodeOutcomingEdges(long long NodeId) {
    //NodeEdgeMap is an unordereded_map
    NodeEdgeMap::iterator it = NodeOutcomingEdges.find(NodeId);
    if (it != NodeOutcomingEdges.end()) {
        return it->second;
    }
    return 0;
}
或者,返回boost::optional,可以为空


但是,您不应该仅仅因为您希望调用方能够引用存储在映射中的同一对象并能够修改它而返回引用,就应该返回引用。否则,返回副本或常量引用会更好。

这只是一种可能的方法:在Graph类中,定义EdgeSet类型的空成员变量,并使用某些属性将其标识为空,例如mEmptyFlag布尔值:

EdgeSet& Graph::GetNodeOutcomingEdges(long long NodeId) {
    //NodeEdgeMap is an unordereded_map
    NodeEdgeMap::iterator it = NodeOutcomingEdges.find(NodeId);
    if (it != NodeOutcomingEdges.end()) {
        return *(*(it)).second;
    }
    static EdgeSet emptySet;
    return emptySet;
}
class Graph {
   ...
   static EdgeSet mEmptyNode(params defining empty node here);
   ...
}

EdgeSet Graph::GetNodeOutcomingEdges(long long NodeId) {
    //NodeEdgeMap is an unordereded_map
    NodeEdgeMap::iterator it = NodeOutcomingEdges.find(NodeId);
    if (it != NodeOutcomingEdges.end()) {
        return *(*(it)).second;
    }
    return Graph::mEmptyNode;
}

callerFunct {
     EdgeSet& OutcomingEdges = RoadGraph.GetNodeOutcomingEdges(Expandee.GetId());
     if (OutcomingEdges.mEmptyflag==true) {
            deal with empty node here
     } else {
          ....
     }
 }

或者更适合于封装,隐藏mEmptyFlag并为EdgeSet提供一个IsEmpty函数。

为什么不发布迭代器?VC++有一个长期存在的错误,允许将非常量引用绑定到临时变量,这是无效的C++,您想返回哪个?引用还是副本?只要g++抛出那个错误,我就知道代码有问题,我只是不知道如何优雅地修复它。你可以使用boost::Optional这既不是引用也不是副本。是的,但通过这种方式,他可以用标准方式验证对象是否存在于他的映射中。我不确定返回一个具体但空的对象是否完全正确。从我调用该方法的位置看不到NodeOutCommingEdge对象。如何测试end?NodeEdgeMap::iterator Graph::end{return nodeOutCommingedges.end;}为什么要修改我?我认为我在这里给出的解决方案是完全有效的。我想我会这么做。似乎是最好的治疗方法,即使这意味着使用原始指针。谢谢。问题是调用方无法访问函数中创建的静态对象,因此无法使用它检查是否返回了错误。静态对象是否可以是常量,以便我确定没有人会对其调用非常量方法?如果是这样,我认为这是给出的最优雅的解决方案。static和const是多余的。使用任意一个,const都可以。正如我在最后提到的,您可以将标志设置为私有,并提供一个IsEmpty函数。如果您想从GetNodeOutCommingEdge返回一个非常量引用,静态对象不能是常量。