【问题标题】:how to create unique_ptr from inherited parent class如何从继承的父类创建 unique_ptr
【发布时间】:2017-07-24 21:58:21
【问题描述】:

有没有办法从继承的类之一创建unique_ptr

我需要能够向经理“注册”MouseListeners,但我不知道如何创建继承的MouseListenerunique_ptr

错误是找不到从Window *MouseListener 的转换。我尝试了static_cast,但这会产生其他错误。我还尝试将raw pointer 传递给addMouseListener,它确实有效,但在您关闭程序时出错,因为我认为它没有创建导致delete 失败的适当内存。

还使用std::move() 转移所有权,导致监听器不触发事件。

// 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;

错误输出

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;
    ^

更新:

取消引用this 增加了一个新问题,其中添加变量listener 你必须添加到std::move(),这会导致所有权更改,如上所述导致事件不触发。

【问题讨论】:

  • 1.你读过错误信息吗? 2. 创建minimal reproducible example
  • 我指定了这个实现的错误。 "它找不到从 Window*MouseListener 的转换。我将发布错误日志以更加清楚,以防人们错过它。
  • MouseListener的构造函数是什么?
  • 这三个都显示在错误日志中。如果需要,我可以将其添加到问题中。
  • @Matthew 您需要添加所有类型的定义。但是删除不需要演示问题的类型的使用。如果不需要,也删除定义的部分。换句话说,创建一个minimal reproducible example

标签: c++ inheritance unique-ptr


【解决方案1】:

make unique 生成该类型的对象并返回指向它的指针。

它不会将预先存在的指向对象的指针包装到唯一的指针中。

您的addMouseListener(std::unique_ptr&lt;MouseListener&gt;) 函数取得了侦听器的所有权。在这里传递预先存在的对象通常不是一个好主意。

可能Window 不应该从MouseListener 继承,而是创建一个MouseListener,该MouseListener 又具有指向Window 的指针,并以某种方式进行生命周期管理以确保Window 活着,或者我们断开连接当Window 死时。

MouseListener 应该中继消息到窗口,而不是窗口。

【讨论】:

    【解决方案2】:
    std::make_unique<MouseListener>(this)
    

    这会分配一个新的MouseListener 实例,并将this 作为构造函数的参数。正如错误消息所解释的那样,没有构造函数 MouseListener:MouseListener(Window*) 或任何其他带有 Window* 可以隐式转换的参数的构造函数。

    您可能不打算创建一个新的MouseListener 实例,而是想要一个指向this 的唯一指针。您可以使用构造函数explicit unique_ptr(pointer p) 创建unique_ptrthis

    std::unique_ptr<Window>(this)
    

    这个指针可以传递给MouseManager::addMouseListener。请注意,虽然从派生唯一指针的转换是隐式的,但基唯一指针不能直接从裸派生指针构造,因为构造函数是显式的。


    请注意,创建一个指向this 的唯一指针可能是一个可疑的想法。它将Window 对象的创建限制为使用new,并且显然(从分配代码的角度来看)泄漏了指针。没有其他代码可以拥有任何窗口(除非从最初存储窗口的容器中移出),并且您永远不能拥有自动实例。

    【讨论】:

    • 所以如果我理解你正确地从MouseListener 继承Window 是好的,但使用像全局MouseManager 这样的东西?
    • MouseListener继承Window违反了单一责任原则。使用组合可能是一种不那么臭的设计。
    • 好吧,在阅读了组合之后,您似乎在说在 Window 类中包含一个变量 MouseListener 是个好主意?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 2019-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多