1

私はプロジェクトに取り組んでおり、最近、特に厄介なセグメンテーション違反に遭遇し始めました。ここにいくつかの背景があります:

1-私は以下をテストした「注文」のキューを持っています:a-いっぱいになり(0注文、1注文、および多くの注文)、isEmpty()がtrueを返すまで削除され、他のキューにこれらがいっぱいになります結果(これはプログラムの動作を複製します)

2--gdbからこれを見つけました:

(gdb) run
Starting program: /Users/Nicholas M. Iodice/Dropbox/tufts/noz2/noz2/a.out 
Reading symbols for shared libraries ++......................... done
order added 1

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: 13 at address: 0x0000000000000000
0x0000000100003a66 in Queue::remove (this=0x7fff5fbffaa0) at Queue.cpp:85
85      ElementType retVal = front->order;
(gdb) where
#0  0x0000000100003a66 in Queue::remove (this=0x7fff5fbffaa0) at Queue.cpp:85
#1  0x0000000100002c08 in Packer::packItem (this=0x7fff5fbffaa0, time=1) at Packer.cpp:88
#2  0x0000000100002e3f in Packer::update (this=0x7fff5fbffaa0, time=1) at Packer.cpp:131
#3  0x0000000100002e9c in PackerManager::update (this=0x7fff5fbffaa0, i=1) at Packer.cpp:295
#4  0x0000000100001ffa in Manager::run (this=0x7fff5fbff830, careAboutSupreme=false) at Manager.cpp:126
#5  0x000000010000511a in main (argc=0, argv=0x7fff5fbffb48) at main.cpp:173
(gdb) 

「orderadded1」は、私が追加したログです。これは、「Fetcher」クラスが「PackerManager」クラスに注文を送信するときに発生します。「PackerManager」クラスは、注文を追加する「Packer」オブジェクトを決定します。デバッグの目的で、すべての注文が1つの「Packer」オブジェクトを経由するようにコードを変更しました。

3-これは、「Packer」オブジェクトがpackItem(キューからremove()を呼び出す)を呼び出すときに、そのキューには1つのオーダーしかないことを意味します。これらのクラスの外でこれをテストしましたが、正常に動作します。

  1. 関連するコードは次のとおりです。

「キュー」から

Queue::Queue()
{
    front = NULL;
    back = NULL;

    //head = NULL;
    //tail = NULL;
    count = 0;
}

//instert to back of queue
void Queue::insert(ElementType order)
{
    if(isEmpty()){
        back = new Node;
        back->order = order;
        back->next = NULL;
        front = back;
    }else{
        Node* tmp = new Node;
        tmp->order = order;
        back->next = tmp;
        back = back->next;
        back->next = NULL;
    }
    count++;
}

//checks if head & tail = NULL
bool Queue::isEmpty()
{
    if(front == NULL && back == NULL){
        return true;
    }
    return false;
}

この行にsegfaultをスローします: "ElementType retVal = front-> order;"

ElementType Queue::remove()
{
    if(isEmpty()){
        cout << "\n\tYou cannot remove from an empty Queue... Exiting.\n\n";
        exit(1);
    }

    ElementType retVal = front->order;
    //delete front;
    if(front == back){
        front = NULL;
        back = NULL;
    }else{
        front = front->next;
    }

    count --;
    return retVal;
}

このコードは、キューからremoveを呼び出します。それが呼んでいるのは「regularOrders」です

//retreives next order to begin packing
void Packer::packItem(int time)
{
    if( careAboutSupreme && !supremeOrders.isEmpty() ){
        orderBeingPacked = supremeOrders.remove();
        orderBeingPackedStartTime = time;

    }else if( careAboutSupreme && isDelayOrderWaiting ){
        orderBeingPacked = orderBeingDelayed;
        orderBeingPackedStartTime = orderBeingDelayedStart + delayDuration;
        delayDuration = 0;
        isDelayOrderWaiting = false;

    }else if( !regularOrders.isEmpty() ){
        orderBeingPacked = regularOrders.remove();
        orderBeingPackedStartTime = time;
    }
}

また、キューは値i=1およびi>1でこのテストに合格します。

#if Q
    Queue q1;
    Queue q2;
    for(int i=0 ; i<5 ; i++){
        Order o;
        q1.insert(o);
    }

    while(!q1.isEmpty()){
        q2.insert(q1.remove());
    }

    sortQueueByOrderNumber(q2);

    while(!q2.isEmpty()){
        q2.remove();
    }
    cout << "Expecting to exit now" << endl;
    q2.remove();
#endif

void sortQueueByOrderNumber(Queue q)
{
    if(q.getCount() == 0){
        return;
    }
    int cnt = q.getCount();
    Order* orderArray = new Order[cnt];
    Order tmpOrder;

    //put orders into array -- after this they are in order, but in an array
    while(q.getCount() != 0){
        tmpOrder = q.remove();
        orderArray[tmpOrder.orderNum-1] = tmpOrder;
    }

    //now we stuff em back into the queue, in order!
    for(int i=0 ; i<cnt ; i++){
        tmpOrder = orderArray[i];
        q.insert(tmpOrder);
    }
    delete[] orderArray;
}

他に何ができるか教えてください。

編集:ここではnullポインタは問題ではないようです:これを追加してみました:

ElementType retVal;
if(front == NULL){
    cout <<"oops!";
}else{
    retVal = front->order;
}

コードは、retVal =front->orderの割り当てに分類されます。したがって、front!= NULLですが、front->orderはメモリの場所としては不適切であると見なされます。

編集2: わかりました、これは奇妙です。clang ++でコンパイルすると、g ++ではなく、実際に機能します(前に別の方法で述べた場合は申し訳ありません)。何?

編集3 わかりました、それで私はこれらのファイルを別のマシンにscpして、それを実行しようとしました。現在、g++とclang++の両方でセグメンテーション違反が発生していますが、キューとはまったく関係のない完全に異なる領域で発生しています。

より広範囲のメモリの問題を引き起こす可能性のある他の何かを見るべきですか?

パッカーオブジェクトの1つを更新しようとすると、セグメンテーション違反が発生するようになりました。以下のコードは、時刻の更新に失敗します(this-> time = time)-これが発生するはずはないと思います。そのため、手元にもっと大きな問題があるのではないかと考えています。また、GDBで確認しましたが、今回はNULLではありません。

void Packer::update(int time)
{
    this->time = time;

    //if orderNum = 0 we havent gotten a real order yet. This is the default from the constructor for Order
    if(orderBeingPacked.orderNum == 0){
        packItem(time);
    }
4

2 に答える 2

3

isEmpty()falseを返すことは、そうでないことを保証するものでfrontはありませんNULL

isEmpty()次のようにアサートを配置します。

bool Queue::isEmpty()
{
    if(front == NULL || back == NULL){
        assert(front == NULL);
        assert(back == NULL);
        return true;
    }
    return false;
}

また、コンストラクターでfrontとの両方を初期化しますbackか?NULL


編集: チェックするもう1つのことは、注文番号が次の一時配列を超えていないかどうかですsortQueueByOrderNumber

void sortQueueByOrderNumber(Queue q)
{
    ...
    int cnt = q.getCount();
    Order* orderArray = new Order[cnt];
    Order tmpOrder;

    //put orders into array -- after this they are in order, but in an array
    while(q.getCount() != 0){
        tmpOrder = q.remove();

        assert(tmpOrder.orderNum >= 1);       // <<<<<<<<<<<<<<<<<<<<<
        assert(tmpOrder.orderNum-1 < cnt);    // <<<<<<<<<<<<<<<<<<<<<

        orderArray[tmpOrder.orderNum-1] = tmpOrder;
    }
    ...
}

EDIT2:もう1つの潜在的な落とし穴:キュー構造をコピーする代入演算子とコピーコンストラクターを実装していることを確認してください。

Queue::Queue(const Queue &other) :
  front(NULL),
  back(NULL),
  count(0)
{
  Node *node = other.front;
  while (node != NULL)
  {
    insert(node->order);
    node = node->next;
  }
}

それ以外の場合、たとえば、呼び出すときにsortQueueByOrderNumber(Queue q)(Maciek Bが指摘するように参照を作成していないと仮定して)、複数のQueueインスタンス間でキューノードを共有します(デフォルトのコピーコンストラクターが機能するのを待つため)。sortQueueByOrderNumber別のQueueインスタンスが(削除された)オブジェクトを指している間に、1つのオブジェクトのすべてのノードがスコープ外(たとえば、の終わり)になりNodeます。

于 2013-03-09T14:18:56.460 に答える
2

この削除はコメント化されていますか?

ElementType retVal = front->order;
//delete front;
if(front == back){
    front = NULL;
    back = NULL;
}else{
    front = front->next;
}

front削除してから使用しないでくださいfront->next。代わりにこれを試してください:

ElementType retVal = front->order;
Node* x = front;
if(front == back){
    front = NULL;
    back = NULL;
}else{
    front = front->next;
}
delete x;

編集:

また、メソッドsortQueueByOrderNumberQueue値ごとにパラメーターを受け取るため、の変更は元のオブジェクトに保存さfrontbackません。Queue署名を次のように変更します。

void sortQueueByOrderNumber(Queue& q)

それでも問題が解決しない場合は、を使用してvalgrindください。それはそれらの記憶の問題を見つけるか、少なくともあなたを正しい方向に向けるべきです。

于 2013-03-09T15:11:24.540 に答える