使用shared_ptr C++双重删除错误

Aha*_*han 1 c++ stl shared-ptr

我有以下课程设计:

struct compare{
template <typename T>
bool operator()(const T& a, const T&b){ return *a < *b;}
};

class Trans;

typedef set<shared_ptr<Trans>, compare > TransPointerSet;

class Place{

  // other data members
 TransPointerSet nextTrans;

public:

  // constructor and other methods including overloaded < operator
  void insertNextTrans(shared_ptr<Trans> t){ nextTrans.insert(t); }
  void removeNextTrans() { nextTrans.clear(); }

};

typedef set<shared_ptr<Place>, compare > PlacePointerSet;

class Trans{

//other data members
PlacePointerSet inPlaces;
PlacePointerSet outPlaces;

public:

//constructor and others including overloaded < operator
void insertInPlace(shared_ptr<Place> p){ 
     inPlaces.insert(p); 
     p->insertNextTrans(shared_ptr<Trans>(this)); }
void insertOutPlace(shared_ptr<Place> p){ //body }
void print() cosnt { //body }

};

class Net{
TransPointerSet acts;
//other data members
public:
//constructor and others
};
Run Code Online (Sandbox Code Playgroud)

这是我的主要测试类是否正常工作.

int main()
{
 shared_ptr<Place> p1 = make_shared<Place>();
shared_ptr<Place> p2 = make_shared<Place>();
shared_ptr<Trans> t = make_shared<Trans>();
t->insertInPlace(p1);
t->insertOutPlace(p2);
t->print();
}
Run Code Online (Sandbox Code Playgroud)

问题是在成功编译之后,在t-> print()正常工作之后,它会以"双重释放或损坏(快速顶部)错误"结束.我意识到错误在于通过首先将p1作为t-> inPlaces的成员创建的循环依赖,其中t作为p1的成员插入.但我需要这两种方式链接.另外,我尝试在t-> print()之后通过一个方法重置类Place中的nextTrans的每个成员,但这不起作用,因为指针在一个集合中.那么有人可以建议任何方法来解决这个问题吗?

Som*_*ude 6

这是因为你无法this像这样制作共享指针.通过这样做,您现在有两个指向该Trans实例的共享指针,它们都指向同一个实例,但它们具有单独的引用计数器.这意味着两者都会尝试delete指针.

你需要使用std::enable_shared_from_this.链接的参考页面有一个非常好的问题示例.


Mic*_*urr 5

这一行在Trans::insertInPlace()

p->insertNextTrans(shared_ptr<Trans>(this)); 
Run Code Online (Sandbox Code Playgroud)

创建一个单独的、不相关的共享指针到同一个对象。您需要std::enable_shared_from_thisTrans类使用:

class Trans: public std::enable_shared_from_this {
    // ....
};
Run Code Online (Sandbox Code Playgroud)

然后在Trans::insertInPlace()

p->insertNextTrans(shared_from_this());
Run Code Online (Sandbox Code Playgroud)