std :: bad_weak_ptr при наследовании std :: shared_from_this из базового класса - PullRequest
0 голосов
/ 23 декабря 2018

Прежде всего, эта проблема связана с совместным использованием 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 отсутствуетstd::make_shared не обнаруживается при наследовании его от родительского класса в libstdc ++ выше версии 6.5.0 при использовании любой версии clang.

Можно ли обойти эту проблему, сохраняя идиому?

Что может быть причиной дефекта здесь?Следует ли об этом сообщать любому багтрекеру (но какой из них наиболее подходящий, поскольку это кажется проблемой совместимости между clang и libstdc ++).

1 Ответ

0 голосов
/ 23 декабря 2018

Как вы уже предположили, проблема действительно заключается в том, что std::shared_ptr не обнаруживает базовый класс std::enable_shared_from_this.Один обходной путь, который работает на моей машине:

std::shared_ptr<myclass> myclass::create() {
    return std::shared_ptr<myclass>{static_cast<myclass*>(new impl{})};
}

Что касается того, где сообщать об ошибке: я бы сообщил об этом на bugtracker llvm, в конце концов, он работает с GCC и в интересах clangs быть совместимымс библиотекой GCC.

...