繁体   English   中英

指针的C ++删除运算符,指针不为空

[英]C++ delete operator on pointer, pointer not nulling

我正在尝试在C ++中实现有向图。 但是,我在使用RemoveEdge函数时遇到了麻烦,在我调用该函数并且它在指针上使用delete运算符并将指针设置为nullptr ,它不会在函数范围之外为nullptr

我不确定我是否已经足够清楚地说明了我的问题,但是也许有些代码会有所帮助。

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

因此,您可以看到我从图表中删除边后,程序崩溃了,由于某种原因,在执行RemoveEdge函数后,它的输出not null 我不确定为什么会发生这种情况,我使用了delete运算符,之后还显式将指针归零。 我在这里做错了什么?

是的,我确定已找到边缘,FindEdge函数会找到正确的边缘对象,并将其从适当的列表中删除,但是delete运算符没有执行我想要的操作。

感谢任何帮助。 提前致谢。

e5是与类中的edge不同的局部变量。

两者都可能指向内存中的同一对象,并不意味着如果您使一个为空,则另一个也将指向空。

考虑这个简单的例子,

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!

希望可以帮助您了解程序的行为!


但是,您可以采取一种技巧。 而不是使用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创建并保存在列表中的指针的别名

使用ip1p2的类似代码是这样的:

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!

要解决功能之外的e5更新,可以使用shared_ptrweak_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() );
    }
};

现在,您可以像这样在main中编写您的部分:

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

注意,我们使用weak_ptr而不是shared_ptr来存储返回值。

您不要使在main.cpp中创建的指针为空。 您只是在RemoveEdge方法中使指针为空。

如果要使main.cpp中的指针为空,则可以例如将其传递给RemoveEdge函数,从而可以消除在列表内部进行搜索的需要。

edgeRemoveEdgee5Main.cpp的是两个不同的局部变量。 为其中一个分配值不会更改另一个值。

FindEdge返回所要复制到指针( 另一份名单本指针的副本 edgeRemoveEdge )。 因此,当您将其设置为NULL仅修改此副本list的指针不受影响。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM