【问题标题】:shared_from_this has empty _M_weak_this even after ownership by std::shared_ptr即使在 std::shared_ptr 拥有后,shared_from_this 也有空 _M_weak_this
【发布时间】:2018-05-26 02:41:00
【问题描述】:

我使用 C++ 智能指针将一个类(我们称之为 A)存储在 std::vector 中(因此向量签名是 std::vector<std::shared_ptr<A>>)。

#include <iostream>
#include <memory>
#include <vector>

class A : std::enable_shared_from_this<A> {
public:
  void doWork();
  std::shared_ptr<A> getSharedRef();
};

void A::doWork() { std::cout << "Working..." << std::endl; }

std::shared_ptr<A> A::getSharedRef() { return shared_from_this(); }

class AManager {
  static std::vector<std::shared_ptr<A>> aList;

public:
  static void init(); // safety because statics
  static void doLotsOfWork();
  static std::shared_ptr<A> createA();
};

std::vector<std::shared_ptr<A>> AManager::aList;

void AManager::init() { aList = std::vector<std::shared_ptr<A>>{}; }

void AManager::doLotsOfWork() {
  for (auto a : aList) {
    a->doWork();
  }
}

std::shared_ptr<A> AManager::createA() {
  std::shared_ptr<A> a = std::make_shared<A>();

  aList.push_back(a);
  return a->getSharedRef(); // <----- EXCEPTION
}

int main() {
  AManager::init();
  AManager::createA();
  return 0;
}

由于某种原因,这会引发std::bad_weak_ptr,并且经过检查,我注意到a,无论出于何种原因,都有一个等于0x0NULL_M_weak_this。因为我已经创建了一个有效的std::shared_ptr 引用该对象,所以它不应该为空。

此外,我知道没有发生内存损坏,因为A(带有变量)在其地址处完全完好无损。

我做错了什么?

【问题讨论】:

  • 你的描述很不错。提供准确重现错误的代码会更好。了解如何创建minimal reproducible example
  • 在这种特殊情况下,MCVE 的最大问题是代码依赖于许多移动部件,我不确定是哪些部件产生了错误。我确实有相关代码的 github 链接,但否则需要几个小时才能启动一个工作示例。
  • 为什么需要 getsharedref() ? (而不仅仅是直接使用 shared_from_this() ?)是因为 A 私有继承吗?如果是,那可能是问题所在......
  • @CalmBit,我知道你来自哪里;创建 MCVE 并不总是那么容易,但它通常是必要的步骤。除了使您的问题非常容易回答之外,您可能会发现您自己解决了这个问题(如果没有,您总是会学到一些东西)。您可能还会发现您问错了问题(您认为问题是由于 X,但实际上是由于 Y)。最后,这听起来可能很荒谬,但创建 MCVE 表明您尊重回答者的时间,不要指望他们会通灵。
  • @AndyG - 我绝对不指望这里有人会通灵!我确实尊重你的时间,尽管我因为在这个单一的错误上浪费了大约 6 个小时而有点受不了——如果我有点粗鲁,请道歉。找到断点后会尽快添加 MCVE。

标签: c++ c++11 vector stl shared-ptr


【解决方案1】:

问题似乎是因为您从 enable_shared_from_this 私下继承

shared_from_this 要求“enable_shared_from_this&lt;T&gt; 应该是 T 的可访问基类。” (根据 [util.smartptr.enab])

通过私有继承,基类不可访问,因此违反了先决条件。我认为这意味着未定义的行为。 Clang 和 GCC 都抛出异常。

解决办法是公开继承。

class A :  public std::enable_shared_from_this<A> {
    //...
};

*在 C++17 中,措辞似乎已移至 [util.smartptr.shared.const],但要求基本相同。

【讨论】:

  • 很遗憾,这在编译时无法检测到。我认为问题在于std::make_shared() 无法检测到派生自enable_shared_from_this 的类,因为它是private,因此引用计数位于单独的内存块中,而不是使用enable_shared_from_this 的成员,这这就是为什么shared_from_this() 认为这是错误的并抛出。既然enable_shared_from_this是CRTP,那么STL库就不能定义一个dummy public验证方法,尝试通过CRTP类调用自己,导致由于隐私问题导致编译失败?
  • 小修正:引用计数与往常一样在同一位置,因为它使用的是make_shared,但enabled_shared_from_this 中的内部成员weak_ptr 没有设置,因为它是私有的。
  • "很遗憾在编译时无法检测到" 那么不要依赖这个非常奇怪的破解工具。有一个您自己初始化的weak_ptr。没有隐藏的、神奇的或隐含的。
猜你喜欢
  • 2014-08-10
  • 1970-01-01
  • 2018-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-10
  • 1970-01-01
相关资源
最近更新 更多