Reading std::map branch won't work in standalone C++

Hello all,

I am sorry, if such a question has already been asked and answered somewhere here, but a half an hour search did not help me at all.

I am currently trying to read a branch (which is a map < string, int >) from a tree in a root file from a standalone program. First I have tried it with a framework which has been developed in our research group which is quite powerful and has always worked perfectly for vector branches. Then I decided to do it all “manually”. Finally, I came up with this code:

#include "TFile.h"
#include "TTree.h"
#include <map>
#include <iostream>

void check()
{
	TFile * f = new TFile("/home/gemo/ntuples/jetcal/NTUP_JETMET.212019._000459.root");
	TTree * MetaTree = (TTree *)(f->Get("qcdMeta/TrigConfTree"));

	std::string meta_L1_NameMap_Name = "LVL1NameMap";

	std::map < std::string, int > * meta_L1_NameMap = new std::map < std::string, int >();
	MetaTree->SetBranchStatus(meta_L1_NameMap_Name.c_str(), 1);
	MetaTree->SetBranchAddress(meta_L1_NameMap_Name.c_str(), &meta_L1_NameMap);

	MetaTree->GetEntry(0);

	std::map < std::string, int >::iterator it;
	for (it = meta_L1_NameMap->begin(); it != meta_L1_NameMap->end(); it++)
		std::cout << it->first << "	" << it->second << std::endl;
}

#ifdef __CINT__
void bla()
{
	gROOT->Reset();

	check();

	gApplication->Terminate();
}
#endif

int main()
{
	check();

	return 0;
}

Running this as a root macro interactively (.x bla.C) works perfectly, the branch is read and the correct (or what I assume to be correct :wink: ) data are printed out. If, however, I compile this as a standalone program, it produces a segmentation fault.

Btw, if I comment out the line, where I set the branch address, the standalone program does run through, but, of course, does not do anything useful.

I really need to be able to read the branch in a standalone program (because it will be part of a huge program which is already there), so switching to interactive running is not an option.

I’ll be grateful for any advice on how to fight this issue!

A small update on the issue. I have now modified the code in such a way that the tree is first cloned and written to another file (bla.root) and then read from it again:

#include "TFile.h"
#include "TTree.h"
#include <map>
#include <iostream>

void check()
{
	TFile * fin = new TFile("/home/gemo/ntuples/jetcal/NTUP_JETMET.212019._000459.root");
	TTree * MetaTree = (TTree *)(fin->Get("qcdMeta/TrigConfTree"));

	TFile * fout = new TFile("bla.root", "RECREATE");
	MetaTree->CloneTree();
	fout->Write();

	delete MetaTree;
	fin->Close();
	fout->Close();
	delete fin;
	delete fout;

	fin = new TFile("bla.root");
	MetaTree = (TTree *)(fin->Get("TrigConfTree"));

	std::string meta_L1_NameMap_Name = "LVL1NameMap";

	std::map < std::string, int > * meta_L1_NameMap = new std::map < std::string, int >();
	MetaTree->SetBranchStatus(meta_L1_NameMap_Name.c_str(), 1);
	MetaTree->SetBranchAddress(meta_L1_NameMap_Name.c_str(), &meta_L1_NameMap);

	MetaTree->GetEntry(0);

	std::map < std::string, int >::iterator it;
	for (it = meta_L1_NameMap->begin(); it != meta_L1_NameMap->end(); it++)
		std::cout << it->first << "	" << it->second << std::endl;
}

#ifdef __CINT__
void bla()
{
	gROOT->Reset();

	check();

	gApplication->Terminate();
}
#endif

int main()
{
	check();

	return 0;
}

Running this interactively as a macro still works with the correct output. Running this as a standalone program leads to no segfault, but also no output. In fact, printing out the size of the map

std::cout << meta_L1_NameMap->size() << std::endl;

after the GetEntry line yields the correct number in the interactive mode and 0 in the standalone mode. I’m quite confused.

Anybody?

For the time being, I have produced a very very very very perverted solution, which I will now implement in my main program, however I really would not like to stick with it for a long time. But at least, this way it works.

#include "TFile.h"
#include "TTree.h"

#include <fstream>
#include <iostream>

#include <cstdlib>

int main()
{
	TFile * fin = new TFile("/home/gemo/ntuples/jetcal/NTUP_JETMET.212019._000459.root");
	TTree * MetaTree = (TTree *)(fin->Get("qcdMeta/TrigConfTree"));

	TFile * fout = new TFile("bla.root", "RECREATE");
	MetaTree->CloneTree();
	fout->Write();

	delete MetaTree;
	fin->Close();
	fout->Close();
	delete fin;
	delete fout;

	ofstream bla ("bla.C");

	bla << "#include <map>" << std::endl;
	bla << "void bla()" << std::endl;
	bla << "{" << std::endl;
	bla << "	gROOT->Reset();" << std::endl;
	bla << "	TFile * fin = new TFile(" << '"' << "bla.root" << '"' << ");" << std::endl;
	bla << "	TTree * MetaTree = (TTree *)(fin->Get(" << '"' << "TrigConfTree" << '"' << "));" << std::endl;
	bla << "	std::string meta_L1_NameMap_Name = " << '"' << "LVL1NameMap" << '"' << ";" << std::endl;
	bla << "	std::map < std::string, int > * meta_L1_NameMap = new std::map < std::string, int >();" << std::endl;
	bla << "	MetaTree->SetBranchStatus(meta_L1_NameMap_Name.c_str(), 1);" << std::endl;
	bla << "	MetaTree->SetBranchAddress(meta_L1_NameMap_Name.c_str(), &meta_L1_NameMap);" << std::endl;
	bla << "	MetaTree->GetEntry(0);" << std::endl;
	bla << "	ofstream fout(" << '"' << "bla.out" << '"' << ");" << std::endl;
	bla << "	std::map < std::string, int >::iterator it;" << std::endl;
	bla << "	for (it = meta_L1_NameMap->begin(); it != meta_L1_NameMap->end(); it++)" << std::endl;
	bla << "		fout << it->first << " << '"' << "	" << '"' << "<< it->second << std::endl;" << std::endl;
	bla << "	fout.close();" << std::endl;
	bla << "	gApplication->Terminate();" << std::endl;
	bla << "}" << std::endl;

	bla.close();

	system("root.exe -l bla.C");

	std::map < std::string, int > meta_L1_NameMap;
	ifstream blafin("bla.out"); std::string trig; int bit;
	while (blafin.good())
	{
		blafin >> trig; blafin >> bit;
		meta_L1_NameMap[trig] = bit;
	}
	blafin.close();

	std::map < std::string, int >::iterator it;
	for (it = meta_L1_NameMap.begin(); it != meta_L1_NameMap.end(); it++)
		std::cout << it->first << "	"<< it->second << std::endl;

	return 0;
}

ok, problem solved. The solution was to do the following in the standalone program

... #include "TPython.h" ... int main() { TPython::Exec( "import PyCintex" ); ... }

and compile it with -lPyROOT. This thread can be closed

Hi,

In order to read the map in a standalone C++, you must load the dictionary for the map explicitly. This can be done via:gROOT->ProcessLine("#include <map>");

Cheers,
Philippe.

PS1. Never ever run gROOT->Reset() from within a function (it should only be used within an unnamed script).

PS1. Do no load Cintex nor PyCintex unless you really really need to (i.e. you are using Python and you have Reflex dictionary)