【问题标题】:Returning a vector by reference通过引用返回向量
【发布时间】:2018-06-16 19:21:09
【问题描述】:

我有以下问题。

typedef std::pair<VertexT,CostT>  LocalEdgeT;
typedef std::vector<LocalEdgeT>   NeighborT;
typedef std::size_t                 VertexT;
typedef double                      CostT;

virtual const NeighborT& getNeighbors( VertexT v) const override   
    {
        std::vector<LocalEdgeT> neighbors;
        //here I'm adding elements, not important for the question
        return neighbors;
    }

我不能让函数在没有引用的情况下返回 NeighborT,因为我必须使用我大学给我的函数,由于某种原因需要引用。

但是当我在 main 中通过以下调用返回它时:

std::vector<NeighborT> test = Object.getNeighbors(arg);

它给出了分段错误,可能是因为我正在返回对局部变量的引用。知道如何修复它,它仍然通过引用返回向量,并且它与我在 main 方法中的函数调用一起工作吗? 此外,我必须使用 c++11 标准进行编译。

一些附加信息:

我只是输入了“对象”,因为我认为它对这个问题并不重要。在我的情况下,函数 getNeighbors 是 Graph 类的成员,它具有一定数量的顶点和从顶点 a 到顶点 b 的所有边的向量。函数 getNeighbors 现在应该找到给定顶点 v 所有邻居。 (从我的角度来看)不建议为类中的每个 Vertex 拥有一个自己的向量。 我确实有一张地图,我保存所有的边缘,它的双“CostT”去那个边缘。 这是完整的课程。

typedef std::size_t                 VertexT;
typedef std::pair<VertexT,VertexT>  EdgeT;
typedef double                      CostT;
    class DistanceGraph
    {
  public:
    typedef std::pair<VertexT,CostT>  LocalEdgeT;
    typedef std::vector<LocalEdgeT>   NeighborT;

  protected:

    std::size_t vertexCount;

  public:
    DistanceGraph( int num_verts= 0)
      : vertexCount(num_verts) {}

    virtual ~DistanceGraph() {}

    std::size_t numVertices() const { return vertexCount; }


    virtual const NeighborT& getNeighbors( VertexT v) const = 0;


    virtual CostT estimatedCost( VertexT from, VertexT to) const = 0;

    virtual CostT cost( VertexT from, VertexT to) const = 0;
};

class CoordinateGraph : public DistanceGraph {
public:

    std::map<  EdgeT, CostT  > allEdges;
    std::vector < std::pair < double, double > > geometricPosition; 

    void setNumVertices( size_t);

    friend std::istream& operator >> (std::istream& in,CoordinateGraph& g);

    virtual const NeighborT& getNeighbors( VertexT v) const override   
    {
        std::vector<LocalEdgeT> neighbors;
        for(size_t i = 0; i < (*this).numVertices(); i++)
        {
            EdgeT edge = std::make_pair(v,i);
            if((*this).allEdges.find(edge) != (*this).allEdges.end())
            {
                neighbors.push_back( std::make_pair(i,(*this).allEdges.find(edge) -> second));
            }
        }
        return neighbors;
    }

    virtual CostT cost( VertexT from, VertexT to) const override
    {
        EdgeT edge = std::make_pair(from,to);
        if((*this).allEdges.find(edge) != (*this).allEdges.end()) return (*this).allEdges.find(edge) -> second;
        else return 10000000;
    }
};

为了再次澄清这一点,我不能让函数 getNeighbors 返回 NeighborT。 我看到的一个解决方案是使每个 Vertex 的邻居成为存储在向量中的类成员。 当我调用上述函数时,上面的代码显然有返回局部变量的问题。

【问题讨论】:

  • 您正在返回对在函数返回之前释放的局部变量 (neighbors) 的引用。免费后使用是UB。
  • 您是否发布了所有相关代码? Object 是什么?
  • 测试例程只是由 Testname(Graph) 调用。我目前没有测试例程的代码。但是只有 NeighborT 测试例程会出现分段错误,现在由于某种原因可以通过 thread_local 关键字解决。
  • 如果需要引用返回,函数返回时变量必须是“活的”。这意味着变量必须是 a)“类成员”或 b)它必须是“静态或 thread_local”(这可能不是您想要的)或 c)分配有 new(这将是一个非常糟糕的设计) .我有一种感觉,您最终陷入这种情况是因为您未发布的某些代码中的设计选择错误。
  • 这个问题需要minimal reproducible example;原始海报给了我们几乎可以肯定被误解的一组约束。这导致了对 OP 真正问题的错误回答。正确的答案可能只是对约束的误解,或者返回一个类局部变量,或者完全是其他的东西。

标签: c++ c++11


【解决方案1】:

由于您似乎很难通过引用返回邻居向量,因此您基本上别无选择,必须将其存储在您的类中。

只需创建一个std::map&lt;VertexT, NeighborT&gt; 类成员来存储它们。

在调用getNeighbors 时检查现有条目并返回现有条目或创建新条目并将其添加到地图中。

【讨论】:

  • 我分享你的想法。这就是我现在处理问题的方式。
【解决方案2】:

您可以做的是使neighbors 线程本地化并在函数的每次调用时将其清除,这样,您可以获得相同的静态语义,而无需昂贵的初始化,假设您当然不是多线程。

virtual const NeighborT& getNeighbors( VertexT v) const override   
{
    thread_local std::vector<LocalEdgeT> neighbors;
    neighbors.clear();

    // stuff...

    return neighbors;
}

【讨论】:

  • 这确实适用于测试例程和我的部分代码!你能解释一下 thread_local 的作用吗?邻居是否在我的程序的整个过程中都在存储中,因此它一次只能存在一个“邻居”向量?
  • @Darragh 这意味着该变量是单个线程的本地变量。所以每个线程都有自己的变量副本(静态意味着每个线程都有相同的变量)。是的,邻居在整个程序中保持活动状态,但不是,有 N 个邻居用于调用您的函数的 N 个不同线程。
  • @darr 请注意,如果有人在这样的工作场所“解决”了这个问题,我会告诉他们寻找另一个解决方案。如果 tney 坚持这是一个好主意,我会鼓励他们到其他地方寻找工作。 999/1000 timea 像这样的黑客会回来咬你。这里真正的问题可能是 OP 由于缺乏理解而错误地陈述了约束,这不是正确的解决方案。
猜你喜欢
  • 2019-06-11
  • 2013-07-07
  • 2019-05-06
  • 2014-06-07
  • 2020-06-18
  • 2012-07-17
  • 2020-02-06
  • 2018-07-27
  • 2018-09-30
相关资源
最近更新 更多