shared pointer assertion fail after iteration in a loop

这一生的挚爱 提交于 2019-12-12 02:57:41

问题


I am new to shared_ptr from boost and am considering to iterate over my set to get the best object. EDIT: added information about first_world

std::set<World::CPtr> first_world = ... // long call, but it gets a set of constant shared pointers to the class World, where various methods exist

   typedef boost::shared_ptr<World const> CPtr;
   World::CPtr best = *(first_world.begin());
   for (World::CPtr lo : first_world) {
     if (best->getValue() >= lo->getValue() ){
       best = lo;
     }
   }

Later I want to use that shared pointer, My program crashes with communicate that Assertion `px != 0' failed. I followed the rules from here, I mean I used a shared pointer as iterator in a loop but then I assign it to another pointer. Is that bad practice, is there better practice?

cout << "name is: " << best->getDefinition() << endl;

回答1:


Nothing's blatantly wrong in what's pasted there, so there's probably going to be a mistake in the long call that creates the set.

For example, it would be easy to mess this up if raw pointers are involved when adding elements to the set. Consider this situation, a concrete illustration of a common mistake that's sort of alluded to in your Best Practices link:

std::set<World::CPtr> first_world;

World* pWorld = new World();

// Bad:
first_world.insert(World::CPtr(pWorld));
first_world.insert(World::CPtr(pWorld));

// Oops!! You now have two independently refcounted entries in first_world!

// emplace is just as deadly, but more subtle.
// Now you'll have three shared pointers in your set:
first_world.emplace(pWorld);

If you look through your entries in first_world and see duplicates then you'll know you're in trouble. To avoid mistakes like this, make sure you only construct shared_ptrs from other shared_ptrs (or boost::make_shared).

So that's tip #1: Avoid constructing shared_ptrs from a raw pointers. (That includes the this pointer if Worlds are adding themselves to your set... if you're doing that, better start googling enable_shared_from_this).

Now let's follow that guideline to get expected behavior:

std::set<World::CPtr> first_world;

World::CPtr spWorld1 = boost::make_shared<World>();
World::CPtr spWorld2{spWorld1};

first_world.insert(spWorld1);
first_world.insert(spWorld2);
// Just one element in first_world now, as expected.

Finally, a few (somewhat unrelated) suggestions:

  • std::set as you've declared it is only looking at the address of World objects on the heap when it compares entries. So if you have two different Worlds on the heap that are logically identical then they'll both have distinct entries in the set. Is that your intent? You'll need to plug in your own custom compare function (std::set's second template argument) to do a deep comparison of Worlds if you want to avoid logical duplicates.
  • Check to make sure that first_world isn't empty before looking for the max, otherwise bad things will happen.
  • Standard algorithms are your friend! Consider using the std::max_element algorithm instead of a raw loop. (This makes it easier for other people to reason about what you're doing with a quick glance).


来源:https://stackoverflow.com/questions/35278937/shared-pointer-assertion-fail-after-iteration-in-a-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!