Save a std::map<int,TH1D> to a TFile

I am writing a program in C++ and have a std::map<int,TH1D> that I would like to write to my TFile. I understand that it is possible to write “simple” STL containers such as std::vector<int>; however, I think the TH1D is complicating things. Thanks in advance for the help!


Please read tips for efficient and successful posting and posting code

ROOT Version: Not Provided
Platform: Not Provided
Compiler: Not Provided


For further information, the runtime error given by my program (compiles just fine) is "Error in <TFile::WriteObjectAny>: The class requested (map<int,TH1D>) for the key name "name" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (map<int,TH1D>). No data will be written."

I have tried adding a line that says

gInterpreter->GenerateDictionary("map<int,TH1D>", "map");

but that gives me several compile time errors

Hi,

as a work around, histograms can be saved to a TTree :slight_smile:

I can reproduce the error. Wrapping the map inside a class like the following do not help. Following the example in root/tutorial/tree/dictionary do not work either.

#include <map>
#include <memory>
#include <TH1D.h>

class myclass{
  public: 
    std::map<int, std::unique_ptr<TH1D> > m; 
};

After a quick look in the forum, there are recent posts regarding the function Generate Dictionary, and it seems to be intended for testing purposes.

Best,
Alvaro

Hi Alvaro! Thanks for the reply and the time you spent checking this out!

I thought about a TTree as well; it’s a good idea. However, I was curious how to generate the dictionary if I wanted to avoid the TTree for whatever reason (or some other alternative which would allow me to save a container [like a map] directly).

Hi,

I tried to generate dictionary for the following class but it does work only if the data is saved into a TTree. If it is saved as object into a TFile, it can not be retrieved.

class myclass{
public: 
  int i; 
  TH1D* h; 
};

I hope you find a way :slight_smile:

Best,
Alvaro

I appreciate the time you put into this. If I ever manage to figure it out, I’ll try to post a solution here.

gInterpreter->GenerateDictionary("map<int,TH1D>", "map"); seems to work just fine. What’s the error you see?

I’m not sure what the issue was before. I just got it to compile with no errors. However, I still get runtime errors. Essentially the code is:

#include<map>
#include "TFile.h"
#include "TH1D.h"
#include "TInterpreter.h"

int main()
{
  TFile f("output.root");
  map<int,TH1D> m;
  /* fill the map */
  gInterpreter->GenerateDictionary("map<int,TH1D>", "map");
  f.WriteObject(&m, "name");
  return 0;
}

And the error I am getting is:

Warning in cling::IncrementalParser::CheckABICompatibility():
  Possible C++ standard library mismatch, compiled with __GLIBCXX__ '20150623'
  Extraction of runtime standard library version was: '20200408'
Error in <TFile::WriteObjectAny>: The class requested (map<int,TH1D>) for the key name "name" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (map<int,TH1D>). No data will be written.

The program finishes running after the error message and the exit code is 0

Edit:
I originally did not include this in the post, but since it may now be relevant:
ROOT Version: 6.24/08
Platform: Linux x86_64
Compiler: c++ (GCC) 9.3.1 20200408 (Red Hat 9.3.1-2)

This indicates that there is a mismatch between the way your verison of ROOT was build and the available compiler.

These are the relevant lines in my makefile:

EXE = ./name
SRC = ./name.cpp

CXX = $(shell root-config --cxx)
CXXFLAG = $(shell root-config --cflags --libs | sed -e 's.-std=c++11.-std=c++14.')

$(EXE): $(SRC)
$(CXX) $(SRC) $(CXXFLAG) -o $(EXE)

Is the issue that I am using c++14 instead of c++11? My program uses features from the c++14 standard and I don’t have permissions to reinstall ROOT on the machine I am compiling and running the code on. Does this mean I am out of luck?

As a general rule, you need to compile your C++ programs using the same C++ standard version that was used to build the ROOT installation on your system (root-config --cflags | grep std).