I am trying to understand why there is a bad_weak_ptr
exception when calling shared_from_this
.
#include <memory>
#include <iostream>
class parent : public std::enable_shared_from_this<parent>
{
public:
void compare(std::shared_ptr<parent> const& p2)
{
std::cout << (this->shared_from_this() == p2->shared_from_this());
}
};
class child1 : public parent
{};
class child2 : public parent
{};
class child3 : public child1, public child2
{};
void compare(parent& p1, parent& p2)
{
std::cout << &p1 << " : " << &p2 << "\n";
std::cout << (&p1 == &p2);
}
void compare(std::shared_ptr<parent> const& p1, std::shared_ptr<parent> const& p2)
{
compare(*p1, *p2);
// p1->compare(p2); // bad_weak_ptr
// auto p = p1->shared_from_this(); // bad_weak_ptr
}
void compareusingchild(std::shared_ptr<child1> const& c1, std::shared_ptr<child2> const& c2)
{
compare(c1, c2);
}
int main()
{
std::shared_ptr<child3> c3 = std::make_shared<child3>();
try
{
compareusingchild(c3, c3);
}
catch (std::exception& e)
{
std::cout << e.what();
}
return 0;
}
I found that by making class parent
inheritance virtual, this problem doesn't seem to persist. Why isn't this a compile time error? something like 'ambiguous function call' when it could not find the correct inherited parent?
An API containing just the parent class cannot know in advance the inheritance hierarchy and call to compare method (in parent) will cause run-time error. Is it possible to make such errors compile time detectable?
Ok Now I see what is the problem.
Diamond problem disables
shared_from_this()
.Under the hood (for MSVC 2017) you can find something like this:
So basically when template is generated, it checks if conversion from
child3 *
tostd::enable_shared_from_this<parent> *
is possible. If it is possible, internal weak pointer is set otherwise nothing is done.Now since there is an ambiguity simple conversion is not possible
std::is_convertible
returns false andshared_from_this
is not enabled (set to proper value).Here is a proof: https://godbolt.org/z/V2AzLk
prints:
So basically ambiguity doesn't cause compilation issue it just doesn't enable this functionality.