1

C++で有向グラフを実装しようとしています。ただし、RemoveEdge関数に問題があります。関数を呼び出し、ポインターに対してdelete演算子を使用し、ポインターをに設定した後nullptr、関数のスコープ外でnullになりません。

問題を十分に明確に述べたかどうかはわかりませんが、コードが役立つかもしれません。

Graph.h

template<class TVertex, class TEdge, class TWeight>
class Graph
{
protected:
    std::list<Vertex<TVertex, TEdge, TWeight>*>* _Vertices;
    std::list<Edge<TVertex, TEdge, TWeight>*>* _Edges;
public:
    Graph();
    int TotalVertices();
    int TotalEdges();
    std::list<Vertex<TVertex, TEdge, TWeight>*>* Vertices();
    std::list<Edge<TVertex, TEdge, TWeight>*>* Edges();

    Vertex<TVertex, TEdge, TWeight>* FindVertex(const TVertex&);
    Vertex<TVertex, TEdge, TWeight>* InsertVertex(const TVertex&);
    void RemoveVertex(const TVertex&);

    Edge<TVertex, TEdge, TWeight>* FindEdge(const TEdge&);
    Edge<TVertex, TEdge, TWeight>* InsertEdge(const TVertex&, const TVertex&, const TEdge&, const TWeight&);
    void RemoveEdge(const TEdge&);
};

Graph.FindEdge()

template<class TVertex, class TEdge, class TWeight>
Edge<TVertex, TEdge, TWeight>* Graph<TVertex, TEdge, TWeight>::FindEdge(const TEdge& label)
{
    Edge<TVertex, TEdge, TWeight>* edge = nullptr;
    std::list<Edge<TVertex, TEdge, TWeight>*>::iterator it;

    for(it = this->_Edges->begin(); it != this->_Edges->end(); ++it)
    {
        if(label == (*it)->Label())
        {
            edge = *it;
            break;
        }
    }

    return edge;
}

Graph.RemoveEdge()

template<class TVertex, class TEdge, class TWeight>
void Graph<TVertex, TEdge, TWeight>::RemoveEdge(const TEdge& label)
{
    Edge<TVertex, TEdge, TWeight>* edge = this->FindEdge(label);
    if(edge == nullptr)
        return;

    this->_Edges->remove(edge);
    edge->Source()->RemoveEdge(edge);
    edge->Destination()->RemoveEdge(edge);

            // Problem is here, why isn't this working like I think it should?
    delete edge;
    edge = nullptr;
}

Main.cpp

// created graph
// added vertices
// added edges
Edge<string, string, int>* e5 = graph->InsertEdge("Oshawa", "Toronto", "E5", 5);
graph->RemoveEdge("E5");
cout << ((e5 == nullptr) ? "null" : "not null") << endl; // this outputs not null

グラフからエッジを削除するとプログラムがクラッシュすることがわかりますが、何らかの理由でnot null、RemoveEdge関数の実行後にプログラムが出力されます。なぜこれが発生しているのかわかりません。削除演算子を使用し、その後でポインターを明示的にnullにしました。私はここで何が間違っているのですか?

はい、確かにエッジが見つかりました。FindEdge関数は正しいエッジオブジェクトを見つけて適切なリストから削除しますが、削除演算子は私が望んでいることを実行していません。

助けに感謝します。前もって感謝します。

4

5 に答える 5

5

e5edgeクラス内とは異なるローカル変数です。

どちらもメモリ内の同じオブジェクトを指している可能性がありますが、一方をnullにすると、もう一方もnullを指すという意味ではありません。

この簡単な例を考えてみましょう。

int i = 10;
int *p1 = &i;
int *p2 = p1;

//here p1 and p2 points to the same object in memory which is i
p1 = nullptr; //it makes only p1 point to null

//here only p2 points to i
cout << *p2 << endl; //ok
cout << *p1 << endl; //dangerous - undefined behaviour!

それがあなたのプログラムの振る舞いを理解するのに役立つことを願っています!


ただし、実行できるトリックが1つあります。を使用する代わりに、をT*使用するT*&と、期待どおりの結果が得られます。

Edge<string, string, int>* & e5 = graph->InsertEdge("Oshawa", "Toronto", "E5", 5);
//                         ^ see this

graph->RemoveEdge("E5");
cout << ((e5 == nullptr) ? "null" : "not null") << endl;

これは、クラス内のオブジェクトへの参照であり、それ自体は別のオブジェクトではなく、作成してリストに保存するポインタのエイリアスe5のようなものであるため、機能するはずです。InsertEdge

ip1を使用した類似のコードは次のp2ようになります。

int i = 10;
int *p1 = &i;
int* & p2 = p1; //now it is a reference to p1, i.e an alias  of p1

//here p1 and p2 points to the same object in memory which is i

p1 = nullptr; //it makes only p1 point to null

//here both p1 and p2 points to null

 if ( p1 == nullptr)
       cout << "p1 points to null" << endl;
 if ( p2 == nullptr)
       cout << "p2 points to null" << endl;
 if ( p1 == p2)
       cout << "p1 and p2 are equal" << endl;

出力:

p1 points to null
p2 points to null
p1 and p2 are equal

デモ: http: //ideone.com/ARiIl

これらにも注意してください:

//after p1 = nullptr
cout << *p2 << endl; //dangerous - undefined behaviour!
cout << *p1 << endl; //dangerous - undefined behaviour!
于 2011-12-06T07:44:00.967 に答える
1

shared_ptr関数外のe5の更新を解決するには、次を使用できますweak_ptr

template<class TVertex, class TEdge, class TWeight>
class Graph
{
  typedef Vertex<TVertex,TEdge,TWeight> VextexType;
  typedef Edge<TVertex,TEdge,TWeight> EdgeType;

  typedef shared_ptr<VertexType> VertexPtr;
  typedef shared_ptr<EdgeType> EdgePtr;

protected:
    std::list< VertexPtr >* _Vertices;
    std::list< EdgePtr >* _Edges;
public:
    Graph();
    int TotalVertices();
    int TotalEdges();
    std::list<VertexPtr>* Vertices();
    std::list<EdgePtr>* Edges();

    VertexPtr FindVertex(const TVertex&);
    VertexPtr InsertVertex(const TVertex&);
    void RemoveVertex(const TVertex&);

    EdgePtr FindEdge(const TEdge&)
    {
        for( std::list<EdgePtr>::iterator it = this->_Edges->begin(); it != this->_Edges->end(); ++it)
        {
            if( label == (*it)->Label())
            {
                return *it;
            }
        }
        return EdgePtr();
    }

    EdgePtr InsertEdge(const TVertex&, const TVertex&, const TEdge&, const TWeight&);
    void RemoveEdge(const TEdge& label)
    {
        EdgePtr edge = this->FindEdge(label);
        if(!edge)
           return;

       this->_Edges->remove(edge);
       edge->Source()->RemoveEdge( edge.get() );
       edge->Destination()->RemoveEdge( edge.get() );
    }
};

これで、次のようにメインでセクションを作成できます。

weak_ptr<Edge<string, string, int> > e5( graph->InsertEdge("Oshawa", "Toronto", "E5", 5) );
graph->RemoveEdge("E5");
cout << (e5 ? "null" : "not null") << endl;

shared_ptrではなく、weak_ptrを使用して戻り値を格納することに注意してください。

于 2011-12-06T07:44:05.803 に答える
1

main.cppで作成したポインタをnullにしないでください。RemoveEdgeメソッドでポインタをnullにしているだけです。

main.cppのポインターをnullにしたい場合は、たとえば、それをRemoveEdge関数に渡すことができます。これにより、リスト内を検索する必要がなくなります。

于 2011-12-06T07:44:13.513 に答える
1

edgeinRemoveEdgeinMain.cppe5は、2つの異なるローカル変数です。それらの1つに値を割り当てても、もう1つの値は変更されません。

于 2011-12-06T07:44:25.210 に答える
1

FindEdgeポインタの別のコピー(内)にコピーしているリストに存在するポインタのコピーを返します。したがって、これをこのコピーのみに設定すると、のポインタは影響を受けません。edgeRemoveEdgeNULLlist

于 2011-12-06T07:45:12.357 に答える