I’ve been running into some problems using vectors and maps, and have tried following the advice posted here, but unfortunately without much luck.
I’ve made a loader.C class, which loads all the dictionaries I think I need:
#include <vector>
#include <map>
#include <utility>
#ifdef __MAKECINT__
#pragma link C++ class vector<double>+;
#pragma link C++ class vector<float>+;
#pragma link C++ class vector<int>+;
#pragma link C++ class map<int,vector<int> >+;
#pragma link C++ class map<int,vector<double> >+;
#endif
I then begin the root session with .L loader C+ as the first command. I then load my ntuples and my root macro, which contains lines such as
With this code I have two (known) problems. The first comes in the form of these error messages:
Error in TTree::SetBranchAddress: The class requested (vector<int,allocator >) for the branch “triggerDecisions” refer to an stl collection and do not have a compiled CollectionProxy. Please generate the dictionary for this class (vector<int,allocator >).
I’m confused about why I’m getting them, when I thought I’d generated these dictionaries in my loader.C file.
The second comes in the form of a segmentation fault when I try to access (*l3DetIds).second.
Just for reference, I’m running version 5.18 that came precompiled with CMSSW.
The dictonary for vector of int, float and double are pre-generated and can not be regenarated (i.e. when creating your dictionary you should have seen a note about vector, etc.).
In ROOT v5.20, the loading of this pre-generated dictionary has been automated. In ROOT v5.18, you need explicitly load it by asking the interpreter to execute #include . E.g.root [] #include <vector>
Hi Philippe,
Thanks for the quick reply. After I followed your advice, I got the first problem taken care of, but I’m still having a problem with my maps. The two commands in the interpreter I’m using right now are
and I can now access all members that are of type vector. Unfortunately, I still have segfaults when I try to access the .first and .second members of my maps. I’ve tried asking the interpreter to execute, e.g.
#pragma link C++ class map<int,vector<int> >+;
as well, but that didn’t really help.
Is there anything else I should be loading or passing through the interpreter to get this problem resolved?
Please note that you must initialize the pointer(s), i.e.:map<int,vector<int> > *l3DetIds = 0;
tree->SetBranchAddress("l3DetIds", &l3DetIds); If you do not then ROOT is attempting to write to write random memory is pointed to by l3DetIds.
Thanks again for the response. Unfortunately, I think my problem is more with the data type than it is with the initialization (I still get the same segfault after trying to initialize l3DetIds to zero or as a new map<int,vector >). The macro was generated using a script similar to TTree::MakeClass on the files I’m trying to run on.
I thought the declaration
and the SetBranchAddress command would allow my macro to access the existing *l3DetIds data member from the input root file. Would I still have the problem of trying to write to random memory with a non-initialized data member in this case?
[quote]The macro was generated using a script similar to TTree::MakeClass on the files I’m trying to run on.[/quote]Humm … Important detail . The skeleton generated by MakeClass but the TTree in a mode where you can quickly retrieve the individual elements of the object but can not retrieve the object themselves [This setting is done via the call to SetMakeClass(1) ]. This is because MakeClass was implemented with the case where you would not have access to any C++ code representing the object when trying to access the TTree (via MakeClass).
Thus to solve the problem you might to only comment out the line looking like fChain->SetMakeClass(1); However this will also invalidate all the SetBranchAddress that do not use actual C++ objects (but instead relies on the object decomposition). If you need both, you probably should try MakeProxy instead of MakeClass (and use the latest possible release of ROOT you can:)).