【问题标题】:shared pointer assertion fail after iteration in a loop在循环中迭代后共享指针断言失败
【发布时间】:2016-05-18 15:56:27
【问题描述】:

我是来自 boost 的 shared_ptr 的新手,我正在考虑迭代我的集合以获得最佳对象。 编辑:添加有关 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;
     }
   }

稍后我想使用该共享指针,我的程序崩溃并与断言 `px != 0' 失败通信。我遵循了here 的规则,我的意思是我在循环中使用了一个共享指针作为迭代器,然后我将它分配给了另一个指针。这是不好的做法,有更好的做法吗?

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

【问题讨论】:

  • 你为什么使用boost::shared_ptr,而你显然在使用 C++11?
  • @molbdnilo 为什么不呢?似乎相当无关紧要。上次我检查的类型不一样,使用你的代码库需要的类型是有意义的......
  • 好吧,c++11 不是必需的,我会将其更改为旧标准 - 我想了解的是为什么它不起作用,如何使它起作用。
  • 可以分享first_world的声明吗?它是什么样的容器,元素类型是什么?
  • @MarkWaterman 已更新。很抱歉遗漏了这些明显需要的信息。

标签: c++ pointers boost iterator shared-ptr


【解决方案1】:

粘贴在那里的内容没有明显错误,因此在创建集合的长调用中可能会有错误。

例如,如果在向集合中添加元素时涉及原始指针,则很容易搞砸。考虑一下这种情况,具体说明您的最佳实践链接中提到的一个常见错误:

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);

如果您查看first_world 中的条目并看到重复项,那么您就会知道您遇到了麻烦。为避免此类错误,请确保仅从其他 shared_ptrs(或boost::make_shared)构造 shared_ptrs。

这就是提示 #1:避免从原始指针构造 shared_ptrs。 (这包括 this 指针,如果世界正在将自己添加到您的系列中......如果您这样做,最好开始使用谷歌搜索 enable_shared_from_this)。

现在让我们按照该准则来获得预期的行为:

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.

最后,一些(有些无关的)建议:

  • std::set 正如您所声明的,它仅在比较条目时查看堆上 World 对象的 address。因此,如果堆上有两个逻辑上相同的不同世界,那么它们在集合中都会有不同的条目。这是你的意图吗?如果您想避免逻辑重复,则需要插入您自己的自定义比较函数(std::set 的第二个模板参数)来对 Worlds 进行深度比较。
  • 在查找最大值之前检查以确保first_world 不为空,否则会发生不好的事情。
  • 标准算法是您的朋友!考虑使用std::max_element 算法而不是原始循环。 (这让其他人更容易通过快速浏览来推断您在做什么)。

【讨论】:

    猜你喜欢
    • 2017-11-11
    • 2014-03-14
    • 1970-01-01
    • 2012-05-23
    • 2014-10-31
    • 2023-03-20
    • 1970-01-01
    • 2016-07-29
    • 1970-01-01
    相关资源
    最近更新 更多