I am a bit puzzled about dictionaries for STL containers. There are various things that I don’t understand:
- I use TClass::GetClass to determine if a class have a valid dictionary, but it seems that for std::vector that method always return a non-null value:
root [0] TClass::GetClass("NonExistingClass")
(TClass *) nullptr
root [1] TClass::GetClass("std::vector<NonExistingClass>")
(TClass *) 0x557daf866950
I don’t understand why the vector has a valid TClass, and whether this means that it also have a valid dictionary or not (specifically, valid for I/O on Root files).
- It seems that even without a manually created dictionary an std::vector can be written on a branch. Compiling this code:
#include "TTree.h"
#include "TFile.h"
#include <iostream>
class TestClass{
public:
int i;
};
int main(){
// Write
std::vector<TestClass> v;
void *pv = &v;
TFile *outFile = TFile::Open("test.root", "RECREATE");
TTree *outTree = new TTree("outTree", "");
outTree->Branch("vectBranch", "vector<TestClass>", pv);
for(int i = 0; i < 5; ++i){
v.resize(0);
for (int iv = 0; iv < i; ++iv){
v.push_back(TestClass{iv});
}
outTree->Fill();
}
outFile->Write();
outFile->Close();
delete outFile;
}
with gcc and running it I get no error and an output file containing the data:
$ root test.root
root [0]
Attaching file test.root as _file0...
(TFile *) 0x556946b1b3b0
root [1] .ls
TFile** test.root
TFile* test.root
KEY: TTree outTree;1
root [2] outTree->Print()
******************************************************************************
*Tree :outTree : *
*Entries : 5 : Total = 1065 bytes File Size = 532 *
* : : Tree compression factor = 1.19 *
******************************************************************************
*Br 0 :vectBranch : vector<TestClass> *
*Entries : 5 : Total Size= 667 bytes File Size = 133 *
*Baskets : 1 : Basket Size= 32000 bytes Compression= 1.19 *
*............................................................................*
So it seems that something is written on file, although it might be (or actually is?) garbage. If data is actually garbage, shouldn’t it be safer to raise an error instead of silently going on? If data is good, how can Root write on disk data of a class (TestClass) which supposedly doesn’t have a dictionary (see 1) )?
- To read out data a dictionary seems to be necessary:
#include "TTree.h"
#include "TFile.h"
#include <iostream>
class TestClass{
public:
int i;
};
int main(){
// Read
std::vector<TestClass> *inv;
TFile *inFile = TFile::Open("test.root");
TTree *inTree = (TTree*)(inFile->Get("outTree"));
inTree->SetBranchAddress("vectBranch", &inv);
for(int iEv = 0; iEv < inTree->GetEntries(); ++iEv){
inTree->GetEntry(iEv);
std::cout << "Event " << iEv << ": ";
for(int iv = 0; iv < inv->size(); ++iv){
std::cout << (*inv)[iv].i << " ";
}
std::cout << std::endl;
}
inFile->Close();
}
Running this program gives a segfault:
$ ./a.out
Error in <TTree::SetBranchAddress>: The class requested (vector<TestClass>) for the branch "vectBranch" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<TestClass>) to avoid to write corrupted data.
*** Break *** segmentation violation
Event 0:
This seems reasonable, although I’d say that a dictionary would be needed also for writing so this makes the behavior described in 2) even more puzzling.
I couldn’t find any documentation explaining the details I’m interested in, so I’d be grateful if an expert can shed sone light on these. Thanks.