【问题标题】:Seg fault when deleting temporary pointer删除临时指针时出现段错误
【发布时间】:2013-04-09 20:35:37
【问题描述】:

我使用 gdb 找到了 seg 错误的确切行。它在 dequeue 函数中作为注释记录。

这是整个队列类。

当队列中有两个对象和哨兵时,我在调用dequeue() 时出现段错误。

template <typename T>
void Queue<T>::clear()
{
    while(!isEmpty())
        dequeue();
}

template <typename T>
void Queue<T>::enqueue(const T& x)
{

    if(isEmpty())
    {
        Queue<T>* temp = new Queue<T>;
        m_data = x;
        m_next = temp;
        return;

    }


    Queue<T>* temp = this;

    while(temp->m_next != NULL)
    {
        temp = temp->m_next;
    }
    Queue<T>* node = new Queue<T>();
    temp->m_data = x;
    node->m_next = temp->m_next;
    temp->m_next = node;
    return;
}

template <typename T>
void Queue<T>::dequeue()
{
    if(isEmpty())
        return;
    if(m_next != NULL)
    {
        Queue<T>* temp = m_next;
        m_data = temp->m_data;
        m_next = temp->m_next;
        delete temp; //Seg fault here
    }
    return;
}

template <typename T>
const T& Queue<T>::front() const throw (int)
{
    if(isEmpty())
        throw 0;
    return m_data;
}

template <typename T>
bool Queue<T>::isEmpty() const
{
    return (m_next==NULL);
}

template <typename T>
int Queue<T>::size() const
{
    int size = 0;
    const Queue<T>* temp = this;
    while(temp->m_next != NULL)
    {
        temp = temp->m_next;
        size++;
    }
    return size;
}

抱歉,我以为我已经发布了 Queue 类:

template <typename T>
class Queue : public AbstractQueue<T> {
public:
    Queue(){m_next = NULL;};

    virtual void clear();

    virtual void enqueue(const T& x);

    virtual void dequeue();

    virtual const T& front() const throw (int);

    virtual bool isEmpty() const;

    virtual int size() const;

    ~Queue(){
        clear();
        return;
    };
private:
    T m_data;
    Queue* m_next;
};

并且它继承自这个类:

template < typename T >
class AbstractQueue
{
public:

  // Purpose: clears the queue
  // Postconditions: the queue is now empty 
  // -- PURE VIRTUAL
  virtual void clear() = 0;

  // Purpose: enqueue an element into the queue
  // Parameters: x is the item to add to the queue
  // Postconditions: x is now the element at the end of the queue, 
  // -- PURE VIRTUAL
  virtual void enqueue(const T& x) = 0;

  // Purpose: dequeues 
  // Postconditions: the element formerly at the front of the queue has
  //     been removed
  // Dequeueing from an empty Queue produces no errors, queue remains empty.
  // -- PURE VIRTUAL
  virtual void dequeue() = 0;

  // Purpose: looks at the front of the queue
  // Returns: a reference to the element currently in front of the queue
  // Exception: if the queue is currently empty, throw SOMETHING!!
  // -- PURE VIRTUAL
  virtual const T& front() const = 0;  

  // Purpose: Checks if a queue is empty
  // Returns: 'true' if the queue is empty
  //     'false' otherwise  
  // -- PURE VIRTUAL
  virtual bool isEmpty() const = 0;

  // Purpose: Returns the size of a queue.
  // Returns: the number of elements in the Queue
  // -- PURE VIRTUAL
  virtual int size() const = 0;

  // ----------------

  // Purpose: Destructor
  // -- VIRTUAL
    virtual ~AbstractQueue() {};

};

【问题讨论】:

  • Queue&lt;T&gt;::dequeue()被调用时,m_next已经是一个无效的指针。或者内存在某处被损坏。 (问题发生在其他地方)
  • 发布您的入队代码
  • 发布所有您的队列代码,以及您调用队列方法的代码。
  • 我没有崩溃。也看不到任何错误。也许发布您的主要功能,当然还有 Queue 类本身。你只有上面代码中的方法。

标签: c++ pointers segmentation-fault queue


【解决方案1】:

在这段代码中:

Queue<T>* temp = m_next;
m_data = m_next->m_data;
m_next = m_next->m_next;

您没有检查 m_next 是否为非空(如果您位于列表的末尾),因此您开始取消引用空指针,并且所有赌注都在此时关闭。

【讨论】:

  • 我想isEmpty() 会进行检查。但该代码尚未发布。
  • 是的,isEmpty() 会进行检查。
  • @somethingShiny 现在看看为什么应该发布所有代码。没有它,我们只是在猜测。
【解决方案2】:

对我来说,enqueue() 中的以下行看起来有点奇怪。

Queue<T>* node = new Queue<T>();

它每次都在创建一个新队列。

可能是以下意图吗?

T * node = new T;

【讨论】:

    【解决方案3】:

    好吧,不给你鱼,我教你钓鱼……

    当您收到segmentation fault 时,表示操作系统检测到内存访问错误。 当您使用指针时,这通常发生在 C/C++ 中。指针非常危险,必须小心对待。

    如何检测问题发生在哪里? 好吧,当您的程序收到SEGFAULT 时,Linux 的信息量不是很大,但是它为您提供了很多信息。你只需要知道如何“阅读”它。

    coredump,是发生分段错误时的内存、堆栈和变量的图片。运行它

    gdb myapp core
    

    其中 myapp 是您的应用程序可执行文件,而 core 是核心转储。 现在你会看到类似的东西:

    GNU gdb 19991004
    
    Copyright 1998 Free Software ���.�
    
    Core was generated by `testit'.
    
    Program terminated with signal 11, Segmentation fault.
    
    Reading symbols from /usr/lib/libstdc++-libc6.1-1.so.2...done.
    
    Reading symbols from /lib/libm.so.6...done.
    
    Reading symbols from /lib/libc.so.6...done.
    
    Reading symbols from /lib/ld-linux.so.2...done.
    
    #0  0x823221a in main () at blabla.c:3
    
    10             *i++;       
    

    它将准确地告诉您是哪条线路导致了故障。 如果您想确切知道您是如何到达该行的,请输入bt 这将向您显示从您的应用程序 main() 到实际故障的回溯,包括传递给函数的参数。

    我认为,一旦您确切知道分段错误发生的位置,您将更容易解决它。

    几点说明:

    1. 如果没有创建 coredump。 在控制台中输入:

      ulimit -c unlimited
      
    2. 您需要使用 -g 编译您的程序,以便在 gdb 中启用有意义的符号名称。

    【讨论】:

    • 我使用 gdb 找到了 seg 错误的确切行。
    • 使用 bt 查找传递的参数
    • 你能给我确切的输入行吗?我不确定我是否完全理解您的意思
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-18
    • 1970-01-01
    相关资源
    最近更新 更多