I'm implementing a polymorphic type (call it A
) that I want to have managed exclusively via std::shared_ptr
. To allow using shared_from_this
in the constructor of derived classes, A
is allocated using new
and then initializes a member std::shared_ptr
to itself to manage its lifetime automatically. To help enforce this, I've decided to make the class-specific operator new
private, and plan to use a create()
helper function instead of new
and make_shared
. The design might look a bit funny but it makes sense in context for the UI library I'm working on. A minimal reproducible example is as follows:
struct A {
A() : m_sharedthis(this) {
}
void destroy(){
m_sharedthis = nullptr;
}
std::shared_ptr<A> self() const {
return m_sharedthis;
}
private:
friend std::shared_ptr<A> create();
std::shared_ptr<A> m_sharedthis;
};
std::shared_ptr<A> create(){
auto a = new A();
return a->self();
}
This compiles and works fine. The problem arises when I add the following code to the body of A
:
struct A {
...
private:
void* operator new(size_t size){
return ::operator new(size);
}
void operator delete(void* ptr){
::operator delete(ptr);
}
...
};
Now this fails to compile on MSVC 2017 with a rather cryptic error message:
error C2664: 'std::shared_ptr<A>::shared_ptr(std::shared_ptr<A> &&) noexcept': cannot convert argument 1 from 'A *' to 'std::nullptr_t'
note: nullptr can only be converted to pointer or handle types
What's going on here? Why is the std::shared_ptr
constructor trying to accept only nullptr
suddenly?
EDIT: Yes, in the actual code, the class does derive from std::enable_shared_from_this
, but it was not necessary to reproduce the error.
When I tried your code, I got an entirely different error:
error C2248: 'A::operator delete': cannot access private member declared in class 'A'
And the culprit is this
m_sharedthis(this)
You provide a pointer, but no deleter. So std::shared_ptr
will try to use the default deleter, which likely contains a delete
expression on your type. Since that deleter is unrelated to your class, it cannot access the private operator delete
.
A workaround is to supply a custom deleter
m_sharedthis(this, [](A* a) {delete a;})
The lambda, having been defined in the scope of the class, has access to operator delete
at the point of its definition.
On an unrelated note. Your code as written is going to leak all those objects. Since the objects all hold a strong reference to themselves, how are they ever going to reach a reference count of zero? Consider using std:enable_shared_from_this
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With