带有forward_list的struct,带有指向自身的指针

时间:2017-03-03 16:05:37

标签: c++ pointers iterator

我实现了一个非常简单的图形模型,其中我有一个包含前向列表的结构,其中包含指向它的邻居。这些邻居又是相同类型的结构。

#include <iostream>
#include <vector>
#include <set>
#include <forward_list>
#include <fstream>

using namespace std;

typedef struct Vertex Vertex;

struct Vertex {
    unsigned id;
    forward_list<Vertex*> _next;
};

typedef set<Vertex> Graph;
typedef vector<Vertex*> Index;
typedef pair<unsigned, unsigned> Edge;
typedef forward_list<Vertex*> Neighbors;


// Function:    process_line()
// Purpose:     process a specific line from the file.
// Params:      line to process
Edge process_line(string line){
    unsigned vertex_from;
    unsigned vertex_to;

    int idx = line.find(" ");

    vertex_from = (unsigned)stoul(line.substr(0, idx));
    vertex_to = (unsigned)stoul(line.substr(idx+1, line.length()));

    return make_pair(vertex_from, vertex_to);
}


// Function:    load_graph()
// Purpose:     load graph from file in relation
// Params:      path, and reference to graph and index
bool load_graph(string file_path, Graph &graph, Index &index){
    string line;
    ifstream file(file_path);
    bool foundEmptyLine = false;

    if(file.is_open()){
        while(getline(file, line)){
            if(line.empty()){
                foundEmptyLine = true;
            }

            if(!foundEmptyLine){
                // processing vertexes
                Vertex *vertex = new Vertex;

                vertex->id = stoul(line);
                graph.emplace(*vertex);
                index.emplace_back(vertex);
            }else{
                // Processing relations
                Edge edge = process_line(line);
                Vertex* neighbor = index.at(edge.second);

                // Lookup edge in index
                index.at(edge.first)->_next.push_front(neighbor);
            }
        }
        file.close();
    }else{
        cout << "Unable to open " << file_path;
        return false;
    }

    return true;
}

void print_graph(Graph &graph){
    for(Graph::iterator it = graph.begin(); it != graph.end(); ++it){
        // Print item.
        cout << "Node: " << it->id << endl << "Neighbors:";

        for(Neighbors::iterator neigh = it->_next.begin(); neigh != it->_next.end(); ++neigh){
            // Print item.
            cout << (*neigh)->id;
        }
    }
}


// Entry point.
int main() {
    Graph graph;
    Index index;

    load_graph("graph_1.txt", graph, index);


    print_graph(graph);
}

一直在努力,直到我尝试循环图中的顶点,然后循环顶点的所有邻居。 (print_graph函数)我收到此错误:

  

错误:来自&#39; const_iterator&#39; (又名   &#39; __ forward_list_const_iterator *&gt;&#39;)到&#39;邻居:: iterator&#39; (又名   &#39; __ forward_list_iterator *&gt;&#39;)

提前致谢。

2 个答案:

答案 0 :(得分:2)

问题在于

Graph::iterator it = graph.begin()

将返回类型为Graph::iterator的迭代器,该迭代器等于Graph::const_iterator。请参阅http://en.cppreference.com/w/cpp/container/set(请注意,这已在C ++ 11中更改)。

所以当你打电话时

Neighbors::iterator neigh = it->_next.begin()

这将返回std::forward_list::const_iterator(因为*itconst),当然您无法分配给std::forward_list::iterator

无论如何,我建议在这里使用auto作为类型,并且,因为您无论如何都不需要写访问权限,所以您应该使用cbegin(),它会在任何地方返回const_iterator情况下。

答案 1 :(得分:2)

此错误的原因非常微妙。 std::set的{​​{1}}类型实际上与iterator类型相同。这是有道理的;集合需要始终保证每个元素都是唯一的。如果您可以自由修改元素,它将无法提供保证。

考虑以下一行:

const_iterator

for(Graph::iterator it = graph.begin(); it != graph.end(); ++it){ it,其行为类似于iterator。您无法修改迭代器指向的内容。

您可以按如下方式验证:

const_iterator

然后是这一行:

it->id = 1; // will result in a compilation error
由于上述原因,

for(Neighbors::iterator neigh = it->_next.begin(); neigh != it->_next.end(); ++neigh){ it->_next,因此在其上调用forward_list<Vertex*> const会返回begin()

这是最终导致错误的原因:您无法将const_iterator转换为const_iterator

治愈很简单:只需使用iterator

const_iterator

甚至更好,使用for(Neighbors::const_iterator neigh = it->_next.begin(); neigh != it->_next.end(); ++neigh){

auto

甚至更简单,基于范围的for(auto neigh = it->_next.begin(); neigh != it->_next.end(); ++neigh){ 循环:

for

请注意,修复此特定错误后,您会找到其他错误。您还缺少必要的for (auto const& neigh : it->_next) { // Print item. cout << neigh->id; } ,这会使您的代码与平台相关(即它适用于GCC,但不适用于Visual C ++)。