2010-07-25 50 views
1

我一直在編寫一個測試用例程序來演示我的一個較大程序的問題, 和測試用例有一個原始程序沒有的錯誤。「地址不是來自malloc()」使用電子圍欄的錯誤

這裏的頭文件:

// compiled with g++ -I/usr/local/bin/boost_1_43_0 -Wall -std=c++0x -g test.cpp 

#include <bitset> 
#include <boost/shared_ptr.hpp> 
#include <vector> 

typedef std::vector< std::vector< std::bitset<11> > > FlagsVector; 

namespace yarl 
{ 
    namespace path 
    { 
     class Pathfinder; 
    } 

    namespace level 
    { 
     class LevelMap 
     { 
     // Member Variables 
      private: 
       int width, height; 
       FlagsVector flags; 

      public: 
       boost::shared_ptr<path::Pathfinder> pathfinder; 

     // Member Functions 
      LevelMap(const int, const int); 

      int getWidth() const {return width;} 
      int getHeight() const {return height;} 

      bool getFifthBit(const int x, const int y) const 
      { 
       return flags.at(x).at(y).test(5); 
      } 
     }; 



     class Level 
     { 
     // Member Variables 
      public: 
       LevelMap map; 

     // Member Functions 
      public: 
       Level(const int w=50, const int h=50); 
     }; 
    } 


    namespace path 
    { 
     class Pathfinder 
     { 
     // Member Variables 
      private: 
       boost::shared_ptr<level::LevelMap> clientMap; 

     // Member Functions 
      public: 
       Pathfinder() {} 
       Pathfinder(level::LevelMap* cm) 
       : clientMap(cm) {} 

       void test() const; 
     }; 
    } 
} 

,這裏是實現文件:

#include <iostream> 
#include "test.hpp" 
using namespace std; 

namespace yarl 
{ 
    namespace level 
    { 
     LevelMap::LevelMap(const int w, const int h) 
     : width(w), height(h), flags(w, vector< bitset<11> >(h, bitset<11>())), 
      pathfinder(new path::Pathfinder(this)) 
     {} 



     Level::Level(const int w, const int h) 
     : map(w,h) 
     { 
      map.pathfinder->test(); 
     } 
    } 



    namespace path 
    { 
     void Pathfinder::test() const 
     { 
      int width = clientMap->getWidth(); 
      int height = clientMap->getHeight(); 
      cerr << endl; 
      cerr << "clientMap->width: " << width << endl; 
      cerr << "clientMap->height: " << height << endl; 
      cerr << endl; 
      for(int x=0; x<width; ++x) 
      { 
       for(int y=0; y<height; ++y) 
       { 
        cerr << clientMap->getFifthBit(x,y); 
       } 
       cerr << "***" << endl; // marker for the end of a line in the output 
      } 
     } 
    } 
} 

int main() 
{ 
    yarl::level::Level l; 
    l.map.pathfinder->test(); 
} 

我這個節目與電動欄杆相連,當我運行它,它與此錯誤中止:

ElectricFence Aborting: free(bffff434): address not from malloc(). 

Program received signal SIGILL, Illegal instruction. 
0x0012d422 in __kernel_vsyscall() 

從gdb回溯顯示非法指令在編譯器中Pathfinder的破壞函數,它在破壞其shared_ptr時遇到了問題。任何人都明白這是爲什麼?

回答

4
yarl::level::Level l; 

實例化一個自動Level變量,它在其構造函數構造及其成員pathfinder像這樣:

pathfinder(new path::Pathfinder(this)) 

然後在Pathfinder構造,它需要你通過在Level指針和受讓人那到一個shared_ptr。然後shared_ptr接管這個指針的所有權。

這有幾個原因是不正確的:

  1. 一個shared_ptr應該用來
  2. 如果你想使用shared_ptr,那麼你應該使用它無處不在管理動態分配的對象,而不是自動分配的對象:如它是現在,你通過原始指針(例如到Pathfinder構造,但然後將它們存儲爲shared_ptr秒。這只是打開所有權蠕蟲的大罐。
  3. 分配thisshared_ptr正確的方法是來源於enable_shared_from_this;但請注意,在構造函數中不能從this獲得shared_ptr

shared_ptr被銷燬時,它會嘗試刪除它所管理的指針。然而,在這種情況下,該指針不是指向動態分配的對象(即,分配給new),而是指向自動分配的對象(即,在堆棧上)。因此,錯誤。

如果您不需要某件東西來獲取資源的所有權,那麼使用原始指針(或引用,如果您有該選項)沒有任何問題。

+0

將LevelMap的探路者從shared_ptr更改爲原始指針解決了問題,感謝您的幫助。作爲第二個問題,我在我的原始程序中使用了很多shared_ptrs,實際上這個例子中的原始指針是我唯一使用的非shared_ptr。你會建議將所有其他shared_ptr更改爲引用或原始指針嗎? – Max 2010-07-25 19:31:35

+0

@Max:您應該使用'shared_ptr'和'weak_ptr'來管理_dynamically allocated_對象。只是不要使用它們來管理自動分配的對象。 – 2010-07-25 19:36:24

2

您正在構建shared_ptr從不應該由shared_ptr管理的指針。 (this指針)

當最後一個shared_ptr的副本被銷燬時,這個內存是空閒的 - 實際上它不應該 - this在這種情況下堆棧。

是有原因的shared_ptr構造是明確的 - 這正是避免常規指針,這是不被shared_ptr的管理,以一個shared_ptr這樣一個被忽視的轉換 - 一旦你通過這樣的指針指向的shared_ptr,你的程序註定要失敗 - 唯一的出路就是刪除你不想刪除的指針。

通常建議直接使用新的構造共享指針 - 例如ptr(new Somethings(x,y,z) - 這樣您不會冒險發生泄漏分配的異常,但未分配給shared_ptr內存的異常。

+0

+1出於同樣的原因。謝謝。 – Max 2010-07-25 19:43:00

1

Level包含一個LevelMap成員變量。當Level被破壞時,它也將銷燬它的LevelMap

另一方面,將指向此LevelMap成員的指針傳遞給Pathfinder,該指針從傳入的指針創建shared_ptr<>。這個新創建的shared_ptr<>認爲它擁有它指向的對象,並且一旦Pathfinder被破壞,它將嘗試銷燬它。

因此LevelMap被毀壞了好幾次。

在該示例中,在堆棧上創建LevelMap。因此,由shared_ptr<>調用的delete可以看到該地址不是來自堆,而是出現錯誤。如果您的真實程序也存在此問題,但所有這些對象都是動態分配的,則可能無法檢測到該錯誤。您稍後會收到沉默的內存損壞和奇怪的崩潰。

+0

+1。原來的問題是我有內存損壞和類似的事情發生,所以這可能幫助我解決這個問題。謝謝。 – Max 2010-07-25 19:34:24

相關問題