Memory issues with vector of pointers to TH1F

Dear experts,

I run into an issue with a vector of pointers to TH1F. I create a couple of TH1F first and put them into a vector, and everything is fine. However, after I use a vector of pointers vector<TH1F*>, for which each element points to a TH1F, something that I don’t understand goes on. The pointers cannot find the TH1F content properly, hence give unexpected results.

I attach the test.C file. Please take a look and I appreciate any hint on this problem.

I also tried creating TH1F* object with “new” and it works totally fine. I kinda know that “new” would keep the memory for the object until I delete ittest.C (675 Bytes)
manually. I am still curious about why the previous case does not work.

Thanks.
Yao


Please read tips for efficient and successful posting and posting code

ROOT Version: 6.22/09
Platform: Linux
Compiler: g++


Hi, Yao

This happens because of the behavior of for(auto hist:HistList). In this case hist will be a copy of the item stored in the HistList. And in your example you are pushing pointers to the copies, which will be destroyed after this loop.

What you want is to loop over list of objects not by value (copying) but by reference with for(auto& hist:HistList). In this case hist will be the same object stored in the list.

See the following modification of your example:

test.C (1.6 KB)

For me it outputs something like:

Histo a is stored at: 0x42dba80
Histo b is stored at: 0x46a1648
Histo c is stored at: 0x46999f0
Histo d is stored at: 0x4699dd8
Histo e is stored at: 0x46b88b0
*********Test auto loop*********:
Pushing histo a with address: 0x7fff7e3e5b30
Pushing histo b with address: 0x7fff7e3e5b30
Pushing histo c with address: 0x7fff7e3e5b30
Pushing histo d with address: 0x7fff7e3e5b30
Pushing histo e with address: 0x7fff7e3e5b30
Trying to get histo name: TObject
Trying to get histo name: TObject
Trying to get histo name: TObject
Trying to get histo name: TObject
Trying to get histo name: TObject
*********Test auto& loop*********:
Pushing histo a with address: 0x46b7910
Pushing histo b with address: 0x46b7cf8
Pushing histo c with address: 0x46b80e0
Pushing histo d with address: 0x46b84c8
Pushing histo e with address: 0x46b88b0
Trying to get histo name: a
Trying to get histo name: b
Trying to get histo name: c
Trying to get histo name: d
Trying to get histo name: e
*********Test i loop*********:
Pushing histo a with address: 0x46b7910
Pushing histo b with address: 0x46b7cf8
Pushing histo c with address: 0x46b80e0
Pushing histo d with address: 0x46b84c8
Pushing histo e with address: 0x46b88b0
Trying to get histo name: a
Trying to get histo name: b
Trying to get histo name: c
Trying to get histo name: d
Trying to get histo name: e
(int) 0

You can see that in auto loop pointers look very different from the ones where the histograms are actually stored, because they are only copies. Which is not the case if we use auto& or for i in... loops.

However, what is still puzzling to me is that initially stored pointers are not identical to ones that we pushing (except very last pointer)… Maybe experts could answer this…

Also interesting to note, that in the root 6.18 your example would produce Seg. Fault. but not just values of uninitialized numbers…
Probably in 6.22 root does not imideately removes object copies after for loop but leaves their dead bodies just to be there for a while? This behavior I also don’t quite understand.

Would be curious to hear the explanation from the experts…

cheers,
Bohdan

Hi @Yao_Yao, @FoxWise,

std::vector<...> automatically reallocates more memory if the vector grows beyond its capacity. Based on the output above, it seems that initial capacity was 4 and adding the fifth element made the vector grow.

Because you are storing elements of type TH1F, an internal memory re-allocation causes objects to be copied to the new buffer (hence the different pointers). This can be avoided by calling reserve() if the number of elements is known in advance.

Accessing unallocated/invalid memory addressed is undefined behavior, and behavior might differ between compiler versions, or OSes.

Cheers,
J.

1 Like