2010-07-25 53 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

相关问题