2

I have the following piece of code:

#include <memory>

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

struct B: public A, public std::enable_shared_from_this<B> {
    std::shared_ptr<B> get() {        
        return enable_shared_from_this<B>::shared_from_this();
    }
};

int main(){
    auto b = std::make_shared<B>();
    auto p = b->get();
}   

Compiling with both clang (15.0.0) and gcc (12.2), and running it leads to a std::bad_weak_ptr exception. I'm curious to understand why that is so. Thanks.

-std=c++20 -O2 -Wall -fsanitize=address
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x7f0e60632941 bp 0x7f0e607fd780 sp 0x7ffdb646eee0 T0)
==1==The signal is caused by a READ memory access.
==1==Hint: this fault was caused by a dereference of a high value address (see register values below).  Disassemble the provided pc to learn which register was used.
    #0 0x7f0e60632941 in abort (/lib/x86_64-linux-gnu/libc.so.6+0x22941)
    #1 0x7f0e60a1ba48  (/opt/compiler-explorer/gcc-12.2.0/lib64/libstdc++.so.6+0xa9a48)
    #2 0x7f0e60a27079  (/opt/compiler-explorer/gcc-12.2.0/lib64/libstdc++.so.6+0xb5079)
    #3 0x7f0e60a270e4 in std::terminate() (/opt/compiler-explorer/gcc-12.2.0/lib64/libstdc++.so.6+0xb50e4)
    #4 0x7f0e60a27336 in __cxa_throw (/opt/compiler-explorer/gcc-12.2.0/lib64/libstdc++.so.6+0xb5336)
    #5 0x4011a3 in std::__throw_bad_weak_ptr() /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/shared_ptr_base.h:96
    #6 0x4011a3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count(std::__weak_count<(__gnu_cxx::_Lock_policy)2> const&) /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/shared_ptr_base.h:1245
    #7 0x4011a3 in std::__shared_ptr<B, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<B, void>(std::__weak_ptr<B, (__gnu_cxx::_Lock_policy)2> const&) /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/shared_ptr_base.h:1548
    #8 0x4011a3 in std::shared_ptr<B>::shared_ptr<B, void>(std::weak_ptr<B> const&) /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/shared_ptr.h:381
    #9 0x4011a3 in std::enable_shared_from_this<B>::shared_from_this() /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/shared_ptr.h:935
    #10 0x4011a3 in B::get() /app/example.cpp:7
    #11 0x4011a3 in main /app/example.cpp:13
    #12 0x7f0e60634082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
    #13 0x4016cd in _start (/app/output.s+0x4016cd)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libc.so.6+0x22941) in abort
==1==ABORTING
Rish
  • 583
  • 1
  • 8
  • 18
  • 2
    Not sure it's a duplicate, but does this help ? https://stackoverflow.com/questions/15549722/double-inheritance-of-enable-shared-from-this – Jeffrey Jan 23 '23 at 02:54
  • No reason to use multiple inheritance for that. `B` is convertible to `A` so `A` is convertible to `B` and you're in a situation where you know you're getting an instance of `B` in `get` so IMHO `std::static_pointer_cast` is a more effective approach. – Captain Obvlious Jan 23 '23 at 03:02

1 Answers1

2

enable_shared_from_this is made to work by various shared_ptr constructors - but only if it's an unambiguous and accessible base class of the class whose pointer is passed to shared_ptr constructor. In your example, enable_shared_from_this base is ambiguous.

[util.smartptr.shared.const]/1 In the constructor definitions below, enables shared_from_this with p, for a pointer p of type Y*, means that if Y has an unambiguous and accessible base class that is a specialization of enable_shared_from_this (20.11.6), then remove_cv_t<Y>* shall be implicitly convertible to T* and the constructor evaluates the statement:

if (p != nullptr && p->weak_this.expired())
  p->weak_this = shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(p));

Emphasis mine.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85