簡體   English   中英

為什么我可以更新 boost::fibonacci_heap 中彈出的元素?

[英]Why can I update a popped out element in a boost::fibonacci_heap?

我正在使用 boost::fibonacci_heap 庫實現快速行進算法,並且我開始使用它們的句柄操作元素。

我寫了下面的基本代碼,它編譯得很好,但我不明白它的行為:

我首先將每個推送元素的句柄存儲在一個數組中。 然后我從堆中彈出第一個元素,並檢查堆大小是否減小。

但隨后我嘗試使用其句柄更新彈出元素的值。 此操作有效(令人驚訝?),並且更新的元素現在位於堆的頂部。 但是堆大小保持不變,因為我沒有正確地推入一個新元素。

那么當一個彈出的元素被更新並返回到堆中時會發生什么? 堆仍然有效嗎?

# include <boost/heap/fibonacci_heap.hpp>
# include <iostream>

using namespace std;
using namespace boost::heap;

struct node
{
  int index;
  double time;

  node(const int& i, double t) : index(i), time(t) {}
};

struct compare_node
{
  bool operator()(const node& n1, const node& n2) const
  {
    return (n1.time > n2.time);
  }
};

int main()
{
  fibonacci_heap< node, compare<compare_node> > heap;
  typedef fibonacci_heap< node, compare<compare_node>  >::handle_type handle_t;
  handle_t tab_handle[10];
  int n;
  double tt[10];

  // assign a set of arbitrary numbers to initialise array tt:
  tt[0] = 5.3;
  tt[1] = 0.25;
  tt[2] = 3.6;
  tt[3] = 1.75;
  tt[4] = 9.1;
  tt[5] = 2.54;
  tt[6] = 3.8;
  tt[7] = 6.1;
  tt[8] = 1.23;
  tt[9] = 7.32;

  // push the values of tt into the heap, and keep track of the handle of each element in the heap:
    for (n=0; n<10; n++)
      {
        tab_handle[n] = heap.push(node(n, tt[n]));
      }


    // display first element in heap
    cout << "first element in heap is :" << heap.top().index << " " << heap.top().time << "\n";

    // check size of the heap
    cout << "size of heap is :" << heap.size() << "\n";

    // remove top element
    heap.pop();

    // check size of the heap
    cout << "size of heap after pop is :" << heap.size() << "\n";

    // display first element in heap
    cout << "first element in heap is now :" << heap.top().index << " " << heap.top().time << "\n";

    // access value of a given element by index:
    cout << "element index 2 has time :" << (*tab_handle[2]).time << "\n";

    // attempt to access the element with handle tab_handle[1]: this element was actually popped out of the heap previously. But I can access it:
    cout << "element index 1 has time :" << (*tab_handle[1]).time << "\n";

    // update the time of an element using its handle. This is quite standard.
    heap.update(tab_handle[2],node(2, tt[2]/10));

    // but now I can also update the element that was popped out of the heap:
    heap.update(tab_handle[1],node(1, tt[1]/10));

    // display first element in heap
    cout << "first element in heap is now :" << heap.top().index << " " << heap.top().time << "\n";

    // check size of the heap
    cout << "size of heap after pop is :" << heap.size() << "\n";

    return 0;

}

終端輸出:

first element in heap is :1 0.25 
size of heap is :10 
size of heap after pop is :9 
first element in heap is now :8 1.23 
element index 2 has time :3.6 
element index 1 has time :0.25 
first element in heap is now :1 0.025
size of heap after pop is :9

實際上,您正在調用Undefined Behavior

在 valgrind¹ 下運行您的程序:

sehe@desktop:/tmp$ valgrind --db-attach=yes ./test
==14185== Memcheck, a memory error detector
==14185== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==14185== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==14185== Command: ./test
==14185== 
first element in heap is :1 0.25
size of heap is :10
size of heap after pop is :9
first element in heap is now :8 1.23
element index 2 has time :3.6
==14185== Invalid read of size 8
==14185==    at 0x400F21: main (test.cpp:47)
==14185==  Address 0x5aa6d78 is 24 bytes inside a block of size 72 free'd
==14185==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14185==    by 0x402789: __gnu_cxx::new_allocator<boost::heap::detail::marked_heap_node<node> >::deallocate(boost::heap::detail::marked_heap_node<node>*, unsigned long) (new_allocator.h:110)
==14185==    by 0x401D2C: boost::heap::fibonacci_heap<node, boost::heap::compare<compare_node>, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::finish_erase_or_pop(boost::heap::detail::marked_heap_node<node>*) (fibonacci_heap.hpp:745)
==14185==    by 0x4015E7: boost::heap::fibonacci_heap<node, boost::heap::compare<compare_node>, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::pop() (fibonacci_heap.hpp:398)
==14185==    by 0x400E1C: main (test.cpp:34)
==14185== 
==14185== 
==14185== ---- Attach to debugger ? --- [Return/N/n/Y/y/C/c] ---- 

看,您正在讀取先前刪除的內存。 哎呀。

任何事情都可能發生。 會發生什么取決於你的運氣,你的電腦等。

¹我使用了代碼的清理版本: Live On Coliru ,因此您可以交叉引用行號

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM