0

I would like to have only one QToolBar instance and modify it many times during the execution of my application. However, I'm concerned about the memory management done by Qt.

Consider the following:

QToolBar toolBar;
std::cout << toolBar.actions().size() << std::endl; // Prints 0
toolBar.addSeparator(); // will add an action
std::cout << toolBar.actions().size() << std::endl; // Prints 1
toolBar.clear();
std::cout << toolBar.actions().size() << std::endl; // Prints 0 again. Good!

Initially, the list of actions in a QToolBar is empty. Thus the first cout prints "0". An internal action is added to that list by "addSeparator". So the second cout prints "1". Finally, "clear", as expected, remove all actions and the last cout prints "0" again.

Now, consider what happens with the "children list":

QToolBar toolBar;
std::cout << toolBar.children().size() << std::endl; // Prints 3. Why?
toolBar.addSeparator(); // will add an action
std::cout << toolBar.children().size() << std::endl; // Prints 5. "addSeparator" has added two children.
toolBar.clear();
std::cout << toolBar.children().size() << std::endl; // Still prints 5. "Clear" did not remove any children!

Initially the children list has size 3. Then I call "addSeparator" and two guys are added to that list. Ok, I can live with that. However, after a call to "clear" these guys are not removed. For each "addSeparator" or "addWidget" call, two children are added and they are never removed.

I'm using Qt 5.4.1 for MSVC 2013, Windows.


Edit: Adding the code suggested by peppe. Please read the line comments.

QToolBar toolBar;
std::cout << toolBar.children().size() << std::endl; // Prints 3.
toolBar.addSeparator();
std::cout << toolBar.children().size() << std::endl; // Prints 5. "addSeparator" has added two children.

auto actions = toolBar.actions();

for (auto& a : actions) {
    delete a;
}

std::cout << toolBar.children().size() << std::endl; // Now this prints 4. Shouldn't be 3?
Community
  • 1
  • 1
Marco
  • 131
  • 1
  • 8

1 Answers1

2

Just take a look at the implementation of addSeparator:

QAction *QToolBar::addSeparator()
{
    QAction *action = new QAction(this);
    action->setSeparator(true);
    addAction(action);
    return action;
}

This creates a new child QAction and adds it to the widget's action list. clear clears the action list, but does not destroy the actions! Hence they'll still be around as children of the toolbar.

Qt doesn't know that you're not using those actions elsewhere -- they're meant to be used across multiple widgets. If you want to reclaim that memory, delete the action returned by addSeparator.

peppe
  • 21,934
  • 4
  • 55
  • 70
  • Suppose that the size of tool bar children list is x. Then I call `toolBar.addSeparator()` many times. After that I iterate through the list returned by `toolBar.actions()` and delete each pointer on this list. The size of tool bar children list must be x again? I'm afraid this is not happening. – Marco Feb 04 '16 at 16:38
  • Can you amend your question showing the code through which you do that? – peppe Feb 04 '16 at 16:48
  • Done. Now instead of calling `toolBar.clear();` I iterate through the actions list and delete each action. Please read the line comments. – Marco Feb 04 '16 at 17:07
  • 1
    Does it still do so if you call `QCoreApplication::processEvents` before getting the children list? Thinking that one of those objects is scheduled for deletion, not just deleted yet. – peppe Feb 04 '16 at 17:15