在复制的std :: list中出现垃圾 [英] Trashes in copied std::list

查看:133
本文介绍了在复制的std :: list中出现垃圾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  class Graph {
public:
typedef unsigned int size_type;
typedef std :: list< size_type>邻居;

保护:
size_type m_nodes_count,m_edges_count;
$ b $ public:
Graph(size_type nodes_count = 0):
m_nodes_count(nodes_count),m_edges_count(0){}

virtual bool is_edge(size_type from,size_type to)= 0;
虚拟邻居邻居(size_type node)= 0;

虚拟图形& add_edge(size_type from,size_type to)= 0;
virtual void delete_edge(size_type from,size_type to)= 0;

size_type nodes_count(){return m_nodes_count; }
size_type edges_count(){return m_edges_count; }

virtual〜Graph(){}
};

类AdjList:public Graph {
private:
typedef std :: list< size_type>行;
std :: vector< Row> m_list;
$ b $ public:
AdjList(size_type nodes_count):Graph(nodes_count){
m_list.resize(nodes_count);
}

AdjList(const AdjList& g):AdjList(g.m_nodes_count){
for(int i = 0; i< nodes_count(); i ++)
std :: copy(g.m_list [i] .begin(),g.m_list [i] .end(),std :: back_inserter(m_list [i]));

$ b $ virtual bool is_edge(size_type from,size_type to)override {
return std :: find(m_list [from] .begin(),m_list [from] .end (),to)!= m_list [from] .end();
}

虚拟图& add_edge(size_type from,size_type to)覆盖{
if(!is_edge(from,to)&&!is_edge(to,from)){
m_list [from] .push_back(to);
m_list [to] .push_back(from);
m_edges_count ++;
}

return * this;


virtual void delete_edge(size_type from,size_type to)override {
m_list [from] .remove(to);
m_list [to] .remove(to);
m_edges_count--;
}

虚拟邻居邻居(size_type node){
return m_list [node];
}
};

但是当我尝试获取 graph.neighbours(v)我收到大量的垃圾:

 (gdb)p图
$ 1 = {< ;格拉夫> = {_vptr.Graph = 0x406210< vtable for AdjList + 16>,m_nodes_count = 3,m_edges_count = 3},m_list = std ::长度为3的矢量,容量3 = {std :: list = {[0]
= 2,[1] = 1},
std :: list = {[0] = 0,[1] = 2},std :: list = {[0] = 0,[1] = 1}}}
(gdb)p graph.neighbours(0)
$ 2 = std :: list = {[0] = 2,[1] = 1,[2] = 4294956560,[ 3] = 2,[4] = 1,
[5] = 4294956560,[6] = 2,[7] = 1,[8] = 4294956560,[9] = 2,[10] = 1 ,
[11] = 4294956560,[12] = 2,[13] = 1,[14] = 4294956560,[15] = 2,
[16] = 1,[17] = 4294956560 ,[18] = 2,[19] = 1,[20] = 4294956560,
[21] = 2,[22] = 1,[23] = 4294956560,[24] = 2, = 1,...

如何解决?

> 可能会被实现细节弄糊涂 的std ::列表。例如。旧的 SGI STL list 已作为循环列表实施。在 list 对象内,只有一个 _List_node< _Tp> 指针,称为 _M_node 。构造函数将最终节点元素的内部 _M_next 指针等于 _M_node 本身。

标准库实现 std :: list 使用此通函实现的目的是避免特殊情况元素(例如,它们也可以使用一个带有 nullptr 下一个指针的标记元素)。 Matt Austern对此有一个很好的 ACCU演示文稿(但该链接目前为损坏的文件,请参阅此处存档的版本
$ b 这个通知解释了为什么 gdb g输出.neighbors()具有重复模式 [0] = 2,[1] = 1,[2] = 4294956560,/ * etcetera * / 。值4294956560只是 std :: list 的内部 _M_node 变量的内存地址,所以如果 gdb 只会执行简单的指针追踪,它会变得困惑。注意它小于 2 ^ 32 ,也就是说你可能要编译32位。

您应该在系统上标准库的< list> 标头中验证。针对 gdb 的错误报告也可能是有序的。


I have graph class that looks like:

class Graph {
  public:
    typedef unsigned int size_type;
    typedef std::list<size_type> Neighbours;

  protected:
    size_type m_nodes_count, m_edges_count;

  public:
    Graph(size_type nodes_count = 0) :
      m_nodes_count(nodes_count), m_edges_count(0) {}

    virtual bool is_edge(size_type from, size_type to) = 0;
    virtual Neighbours neighbours(size_type node) = 0;

    virtual Graph& add_edge(size_type from, size_type to) = 0;
    virtual void delete_edge(size_type from, size_type to) = 0;

    size_type nodes_count() { return m_nodes_count; }
    size_type edges_count() { return m_edges_count; }

    virtual ~Graph() {}
};

class AdjList : public Graph {
  private:
    typedef std::list<size_type> Row;
    std::vector<Row> m_list;

  public:
    AdjList(size_type nodes_count) : Graph(nodes_count) {
      m_list.resize(nodes_count);
    }

    AdjList(const AdjList& g) : AdjList(g.m_nodes_count) {
      for (int i = 0; i < nodes_count(); i++)
        std::copy(g.m_list[i].begin(), g.m_list[i].end(), std::back_inserter(m_list[i]));
    }

    virtual bool is_edge(size_type from, size_type to) override {
      return std::find(m_list[from].begin(), m_list[from].end(), to) != m_list[from].end();
    }

    virtual Graph& add_edge(size_type from, size_type to) override {
      if (!is_edge(from, to) && !is_edge(to, from)) {
        m_list[from].push_back(to);
        m_list[to].push_back(from);
        m_edges_count++;
      }

      return *this;
    }

    virtual void delete_edge(size_type from, size_type to) override {
      m_list[from].remove(to);
      m_list[to].remove(to);
      m_edges_count--;
    }

    virtual Neighbours neighbours(size_type node) {
      return m_list[node];
    }
};

but when I try to get graph.neighbours(v) I get big amount of trash in it:

(gdb) p graph
$1 = {<Graph> = {_vptr.Graph = 0x406210 <vtable for AdjList+16>, m_nodes_count = 3, m_edges_count = 3}, m_list = std::vector of length 3, capacity 3 = {std::list = {[0]
 = 2, [1] = 1},
    std::list = {[0] = 0, [1] = 2}, std::list = {[0] = 0, [1] = 1}}}
(gdb) p graph.neighbours(0)
$2 = std::list = {[0] = 2, [1] = 1, [2] = 4294956560, [3] = 2, [4] = 1,
  [5] = 4294956560, [6] = 2, [7] = 1, [8] = 4294956560, [9] = 2, [10] = 1,
  [11] = 4294956560, [12] = 2, [13] = 1, [14] = 4294956560, [15] = 2,
  [16] = 1, [17] = 4294956560, [18] = 2, [19] = 1, [20] = 4294956560,
  [21] = 2, [22] = 1, [23] = 4294956560, [24] = 2, [25] = 1,...

How to fix that?

解决方案

gdb is probably getting confused by an implementation detail the std::list. E.g. the old SGI STL list was implemented as a circular list. Inside the list object, there is only a singly _List_node<_Tp> pointer called _M_node. The constructor puts the internal _M_next pointer of the final node element equal to _M_node itself.

The reason Standard Library implementations of std::list use this circular implementation is to avoid special cases for the final element (e.g. they could also use a a sentinel element with a nullptr next pointer). Matt Austern has a nice ACCU presentation about this (but the link is currently to a corrupted file, see archived version here).

This circular implementation explains why your gdb output for g.neighbors() has the repeating pattern of [0] = 2, [1] = 1, [2] = 4294956560, /* etcetera */. The value 4294956560 is simply the memory address of the internal _M_node variable of your std::list, so if gdb only does simnple pointer chasing, it will get confused. Notice that it is less than 2^32, i.e. you are probably compiling this for 32-bits.

You should probably verify this in your own <list> header of the Standard Library on your system. A bug report for gdb might also be in order.

这篇关于在复制的std :: list中出现垃圾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆