Skip to content

Conversation

@guitargeek
Copy link
Contributor

The TMultiGraph::Add(TMultiGraph*, Option_t*) overload that adds the graphs in another TMultiGraph to a TMultiGraph is removed without deprecation. It was inconsistent from a memory ownership standpoint. A TMultiGraph always owns all the added graphs, so adding the same graph instances to two TMultiGraphs forcibly led to double-deletes. The ownership behavior could also not be changed, which gets clear from the TMultiGraph destructor, which always calls TList::Delete() on the collection that holds the TGraphs.

No deprecation period is defined, because as the overload unavoidibly leads to double-deletes, it is likely not used. Or at least rarely used, because it can work if one of the two TMultiGraphs is leaked on purpose.

If you want to add all graphs from otherMultiGraph to multiGraph, one should use a for-loop and clone the graphs instead:

for (TObject *gr : *otherMultiGraph) {
   multiGraph->Add(static_cast<TGraph*>(gr->Clone()));
}

Some examle code with the double-delete:

{
   auto mg1 = new TMultiGraph();
   auto mg2 = new TMultiGraph();

   auto gr1 = new TGraph();

   mg1->Add(gr1);

   auto gr2 = new TGraph();

   mg1->Add(gr2);

   mg2->Add(mg1); // This is the Add(TMultiGraph* overload)

   delete mg1;
   delete mg2;
}

This is a spinoff from #13593, triggered by a question from @vepadulano (#13593 (comment)).

The `TMultiGraph::Add(TMultiGraph*, Option_t*)` overload that adds the
graphs in another **TMultiGraph** to a **TMultiGraph** is removed
without deprecation. It was inconsistent from a memory ownership
standpoint. A **TMultiGraph** always owns all the added graphs, so
adding the same graph instances to two **TMultiGraphs** forcibly led to
double-deletes.

No deprecation period is defined, because as the overload unavoidibly
leads to double-deletes, it is likely not used. Or at least rarely used,
because it can work if one of the two TMultiGraphs is leaked on purpose.

If you want to add all graphs from `otherMultiGraph` to `multiGraph`,
one should use a for-loop and clone the graphs instead:

```c++
for (TObject *gr : *otherMultiGraph) {
   multiGraph->Add(static_cast<TGraph*>(gr->Clone()));
}
```

Some examle code with the double-delete:
```c++
{
   auto mg1 = new TMultiGraph();
   auto mg2 = new TMultiGraph();

   auto gr1 = new TGraph();

   mg1->Add(gr1);

   auto gr2 = new TGraph();

   mg1->Add(gr2);

   mg2->Add(mg1); // This is the Add(TMultiGraph* overload)

   delete mg1;
   delete mg2;
}
```
@guitargeek
Copy link
Contributor Author

Note that this method was introduced 20 years ago in 701fbd2 with no added tutorial or other demo, so likely it is not used much. And indeed, the demo in the commit description was letting mg1 leak, to avoid the double-delete. @couet do you maybe remember the original motivation, or have other suggestions to fix this ownership inconsistency? Or is just removing the method fine for you?

Copy link
Member

@vepadulano vepadulano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is a good choice in this case, because the existing API is shown to be a cause of immediate and verifiable bugs. The fact this is communicated clearly in the release notes is enough imho.

@guitargeek guitargeek merged commit 4337eef into root-project:master Jan 13, 2026
31 of 33 checks passed
@guitargeek guitargeek deleted the tmultigraph branch January 13, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants