如果 QMenu 是 unique_ptr,为啥 QAction 不添加到 QMenu?

Posted

技术标签:

【中文标题】如果 QMenu 是 unique_ptr,为啥 QAction 不添加到 QMenu?【英文标题】:Why QAction is not adding to QMenu, if QMenu is unique_ptr?如果 QMenu 是 unique_ptr,为什么 QAction 不添加到 QMenu? 【发布时间】:2015-06-14 18:31:43 【问题描述】:

代码示例:

auto fileMenu = std::make_unique<QMenu>(this->menuBar()->addMenu("First"));
fileMenu->addAction("AFirst");

auto x = this->menuBar()->addMenu("Second");
x->addAction("ASecond");

结果:

我在菜单栏中有 2 个菜单,但在第一个菜单中 - 出于某种原因,没有任何操作。第二个菜单正确有动作。

我尝试了不同的方法,例如类成员指针等,但这是可能的最短示例 - 如果 QMenu 是 unique_ptr,则缺少 QAction。谁能为我解释一下?父窗口是QMainWindow,以防万一。

系统信息: Win8.1 x64,编译器为VS2013,Qt 5.4 x32。

【问题讨论】:

嗯。我希望使用 std::unique_ptr 导致双重删除,因为当父级超出范围时 Qt 将删除子级。 您不应该将QMenu 包裹在unique_ptr 中;它已经由菜单栏管理。 QAction 没有被包裹,QMenu 被包裹在这里。 抱歉,已更正。我正在查看文档中addMenu 的另一个重载,即返回QAction 您的 std::unique_ptr 文件菜单是否超出范围?也许您的 fileMenu 已经被释放但仍连接到父级并且您正在体验 UB。 【参考方案1】:

在这一行:

auto fileMenu = std::make_unique<QMenu>(this->menuBar()->addMenu("First"));

fileMenu 成为一个新的QMenu 对象(使用this constructor)。完全一样:

std::unique_ptr<QMenu> fileMenu(new QMenu(this->menuBar()->addMenu("First")));

然后,您将QAction 添加到这个临时的新菜单中。

第二种情况:

auto x = this->menuBar()->addMenu("Second");
x->addAction("ASecond");

x 成为指向现有菜单的指针。这就是区别。

无论如何,通常你不应该使用std::unique_ptr 持有QObjects。在 Qt 中,有一个约定,您可以通过将父级分配给每个 QObjects 来形成一棵树。父级递归删除其子级,您不应手动管理它们,否则在某些特定情况下可能会导致双重释放。

【讨论】:

不过,您并没有解释为什么第一种方法不起作用而第二种方法起作用...... @peppe:“然后,向这个临时的新菜单添加一个 QAction。”将 QAction 插入到临时对象并不会将其插入到menuBar,这不是很明显吗? 嗯,这不完全是“临时的”。 QMenuBar::addMenu 将创建一个新的 QMenu 作为孩子,并将其返回。那么真正的问题是unique_ptr 将在fileMenu 超出范围时破坏QMenu。 OP还说“试图让uniqueptr成为classmember,所以,它不会超出范围-结果是一样的”,但我还没有看到更新的代码。 @peppe:好的,这不是 C++ 意义上的“临时”。它只是一个新对象,不是子菜单。它是QMenu 返回的 QMenuBar::addMenu。看来,简单地创建一个 QMenu 并以另一个 QMenu 作为父级并不能使其成为子菜单。即使没有使用 unique_ptr 进行管理,它也不会按预期工作。

以上是关于如果 QMenu 是 unique_ptr,为啥 QAction 不添加到 QMenu?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 QMenu:hover 在 Qt Designer 中不起作用

为啥我不能在 C++14 的 lambda 中移动 std::unique_ptr?

当我以 root 身份运行 PyQt 应用程序时,为啥我的 QMenu 中不显示 QIcons?

为啥 std::unique_ptr 重置与赋值不同?

为啥我不能返回对使用模板创建的派生类的 unique_ptr 的引用?

为啥 unique_ptr<T> 不能从 T* 构造?