Reputation: 850
Is there a way to create a unique_ptr
from one of the inherited classes?
I need to be able to "register" MouseListeners
with a manager but I cannot figure out how to create the unique_ptr
of the inherited MouseListener
.
The error is that it cannot find a conversion from Window *
to MouseListener
. I have tried a static_cast
but that produces other errors. I have also tried passing in a raw pointer
to the addMouseListener
which did work but errored when you close the program as I think it did not create the appropriate memory which causes the delete
to fail.
Also using std::move()
transfers ownership which causes the listener to not fire the event.
// Window.h
class Window : public MouseManager, public MouseListener {
public:
Window::Window(std::string title, int32_t width, int32_t height) {
...
this->addMouseListener(std::make_unique<MouseListener>(this)); // ERROR
}
};
// MouseManager.h
void MouseManager::addMouseListener(std::unique_ptr<MouseListener> listener) {
m_listeners.emplace_back(listener);
}
// MouseListener.h
MouseListener() = default;
virtual ~MouseListener() = default;
MouseListener(const MouseListener& listener) = default;
MouseListener(MouseListener&& listener) noexcept ;
MouseListener& operator=(const MouseListener& listener) = delete;
MouseListener& operator=(MouseListener&& listener) = delete;
Error output
In file included from /Users/Programmer/CLionProjects/StormEngine/Engine/Window/Window.cpp:5:
In file included from /Users/Programmer/CLionProjects/StormEngine/Engine/Window/Window.h:8:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:3141:32: error: no matching constructor for initialization of 'MouseListener'
return unique_ptr<_Tp>(new _Tp(_VSTD::forward<_Args>(__args)...));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/Programmer/CLionProjects/StormEngine/Engine/Window/Window.cpp:17:33: note: in instantiation of function template specialization 'std::__1::make_unique<MouseListener, Window *>' requested here
this->addMouseListener(std::make_unique<MouseListener>(this));
^
/Users/Programmer/CLionProjects/StormEngine/Engine/Window/../Events/Listeners/MouseListener.h:19:5: note: candidate constructor not viable: no known conversion from 'Window *' to 'const MouseListener' for 1st argument; dereference the argument with *
MouseListener(const MouseListener& listener) = default;
^
/Users/Programmer/CLionProjects/StormEngine/Engine/Window/../Events/Listeners/MouseListener.h:20:5: note: candidate constructor not viable: no known conversion from 'Window *' to 'MouseListener' for 1st argument; dereference the argument with *
MouseListener(MouseListener&& listener) noexcept ;
^
/Users/Programmer/CLionProjects/StormEngine/Engine/Window/../Events/Listeners/MouseListener.h:16:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
MouseListener() = default;
^
Update:
de-referencing this
adds a new problem where to add the variable listener
you have to std::move()
which causes the change of ownership which as stated above causes the events not to fire.
Upvotes: 0
Views: 1773
Reputation: 238491
std::make_unique<MouseListener>(this)
This allocates a new MouseListener
instance, with this
as an argument to the constructor. As the error message explains, there is no constructor MouseListener:MouseListener(Window*)
or any other constructor with a parameter to which Window*
could be implicitly converted.
You probably didn't intend to create a new MouseListener
instance, but instead want a unique pointer to this
. You can create a unique_ptr
to this
using the constructor explicit unique_ptr(pointer p)
:
std::unique_ptr<Window>(this)
This pointer can be passed to MouseManager::addMouseListener
. Note that while the conversion from a deriver unique pointer is implicit, a base unique pointer cannot be directly constructed from a bare derived pointer, because the constructor is explicit.
Note that creating a unique pointer to this
is probably a dubious idea. It limits the creation of Window
objects to using new
, and apparently (from the perspective of the code that allocates) leaking the pointer. No other code can own any windows (unless moved from the container where it was initially stored), and you can never have automatic instances.
Upvotes: 0
Reputation: 275976
make unique makes an object of that type and returns a pointer to it.
It does not wrap a pre existing pointer to an object into a unique ptr.
Your addMouseListener(std::unique_ptr<MouseListener>)
function takes ownership of the listener. Passing a preexiting object is not generally a good idea here.
Probably Window
should not inherit from MouseListener
but instead create a MouseListener
that in turn has a pointer to the Window
and somehow does lifetime management to ensure the Window
alive stays around, or us disconnected when the Window
dies.
The MouseListener
should relay messages to the window, not be the window.
Upvotes: 1