从基类继承std::shared_from_this时出现std::bad_weak_ptr错误

3

首先,这个问题似乎与使用clang(任何版本)和libstdc ++高于6.5.0版本一起使用有关。

我在我的代码库中使用以下习惯用语来隐藏实现细节:

#include <memory>

class myclass : public std::enable_shared_from_this<myclass> {
  class impl;

protected:
  myclass() = default;

public:
  myclass(myclass&&) = delete;
  myclass(myclass const&) = delete;
  myclass& operator=(myclass&&) = delete;
  myclass& operator=(myclass const&) = delete;
  virtual ~myclass() = default;

  static std::shared_ptr<myclass> create();

  int get();
};

class myclass::impl : public myclass {
public:
  using myclass::myclass;

  int get_impl() {
    return 33;
  }
};

std::shared_ptr<myclass> myclass::create() {
  return std::make_shared<impl>();
}

int myclass::get() {
  return static_cast<impl*>(this)->get_impl();
}

int main() {
  auto ref = myclass::create();
  return ref->shared_from_this()->get();
}

成语使用了一个继承并实现公共基类的私有类。 在Ubuntu 18.04下使用clang++ -O3 -std=c++11 main.cpp && ./a.out运行此代码片段时,会出现以下崩溃输出:
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr

以下是相关的回溯信息:

#0  0x00007ffa76a7de97 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffa76a7f801 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007ffa774728fb in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffa77478d3a in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007ffa77478d95 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007ffa77478fe8 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x0000000000404f7c in std::__throw_bad_weak_ptr() ()
#7  0x0000000000404e92 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count(std::__weak_count<(__gnu_cxx::_Lock_policy)2> const&) ()
#8  0x0000000000404e2f in std::__shared_ptr<myclass, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<myclass, void>(std::__weak_ptr<myclass, (__gnu_cxx::_Lock_policy)2> const&) ()
#9  0x0000000000404df8 in std::shared_ptr<myclass>::shared_ptr<myclass, void>(std::weak_ptr<myclass> const&) ()
#10 0x0000000000403d2c in std::enable_shared_from_this<myclass>::shared_from_this() ()
#11 0x0000000000403ac8 in main ()

测试平台使用以下编译器和标准库:
clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/7.3.0

尽管此代码在其他平台和/或编译器上运行良好:
  • GCC 7.3.0 和 "lib/gcc/x86_64-linux-gnu/7.3.0" 在同一平台上工作
  • Clang 3.8.0 和 "lib/gcc/x86_64-linux-gnu/6.5.0" 在另一个平台上工作
  • Clang 7.0.1 和 "lib/gcc/x86_64-linux-gnu/6.5.0" 在另一个平台上工作
  • Windows MSVC 15.9.4
总的来说,当从父类中继承 std::shared_from_this 时,在使用任何 clang 版本且 libstdc++ 高于版本 6.5.0 时,std::make_shared 不会检测到该继承。 在保持这个惯用法的同时,是否有可能解决这个问题? 可能是什么导致了这个缺陷? 应该将其报告给任何 bugtracker 吗(但哪一个是正确的,因为这似乎是 clang 和 libstdc++ 之间的互操作性问题)?

2
你在使用libc++吗?错误似乎来自于libstdc++,也就是GNU的库,而不是clang的库。无论如何,原因还不确定... - ravnsgaard
1
哦,我的意思是GNU库中的libstdc++,我已经更正了。 - Naios
1个回答

1
正如您所建议的那样,问题似乎确实是std::shared_ptr没有检测到std::enable_shared_from_this基类。在我的机器上有效的一个解决方法是:
std::shared_ptr<myclass> myclass::create() {
    return std::shared_ptr<myclass>{static_cast<myclass*>(new impl{})};
}

关于报告问题的位置:我建议在LLVM bug跟踪器上报告,因为它可以与GCC一起使用,并且与GCC库兼容是clang的利益所在。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接