Array of std::vector

Dear Rooters,

I am trying something I have never seen documented. So probably it is not supported in root. However before giving up I would like to have some expert opinion.

I would like to store an array of std vector in a tree. I am following the usual procedure to fill a tree using a C++ class, building the dictionary and so on.

The following pages are summarising what I am trying to do:

  1. First of all I define the class that I want to store (.h and .cxx follow):

myClass.h (defines the class I want to use to fill the tree)

#ifndef ROOT_myClass
#define ROOT_myClass

#include <vector>

#include "TObject.h"

class myClass : public TObject {

private:
   std::vector<int> vInt;
   std::vector<int> avInt[2];


public:
   myClass();
   virtual ~myClass();

   void addTrk(int i);

   void addTrkA(int i, int pos);

   ClassDef(myClass,1)

};

#endif

and its implemetnation in myClass.cxx

#include "myClass.h"

ClassImp(myClass)

myClass::myClass()
{
    ;
}

myClass::~myClass()
{
    ;
}

void myClass::addTrk(int i){
    vInt.push_back(i);
}

void myClass::addTrkA(int i, int pos){
    avInt[pos].push_back(i);
}
  1. From this class I build the dictionary and the dynamic lib using the following commands (I will not report the Linkdef.h):
c++  -O2 -Wall -fPIC -pthread -m64 -I/opt/root/5.34.36/include -c myClass.cxx
rootcint -f myDict.cxx -c myClass.h LinkDef.h
c++  -O2 -Wall -fPIC -pthread -m64 -I/opt/root/5.34.36/include -c myDict.cxx
c++ -shared -O2 -m64 myClass.o myDict.o -o  libDict.so 
  1. Finally I compile my Main.cpp program:
#include <iostream>

#include "myClass.h"

#include <TSystem.h>
#include <TFile.h>
#include <TTree.h>
#include <TClassTable.h>


using namespace std;

int main(){
    
    if( !TClassTable::GetDict("myClass") ){
        cout << "Loading dict" << endl;
        gSystem->Load("./libDict.so");
    }

    TFile f("out.root", "RECREATE");

    TTree tree("tree", "tree");
    myClass *evt = new myClass();
      
    tree.Branch("evt", "myClass", &evt, 16000, 0);

    for(int i=0; i<100; i++){
        evt->addTrk(i);
        evt->addTrkA(i, 0);
    }
 
    tree.Fill();
   
    f.Write();
    f.Close();

    return 0;

}

Using the command:

g++ -o Main.exe Main.cpp   -Wall -std=c++0x -Wno-write-strings -pthread -m64 -I/opt/root/5.34.36/include -L/opt/root/5.34.36/lib -lGui -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread -pthread -lm -ldl -rdynamic -L/opt/root/5.34.36/lib -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread -pthread -lm -ldl -rdynamic -L./ -lDict
  1. Everything seems to be working and I am able to run. However if I open the tree in a TBrowser and I try to access avInt root crashes saying:

root [2] Fatal: fHasMultipleVarDim[code] violated at line 509 of `/opt/root/root/tree/treeplayer/src/TTreeFormula.cxx'
aborting
#0  0x00007fecf3274a0c in __libc_waitpid (pid=58059, stat_loc=stat_loc
entry=0x7ffd3dc94fd0, options=options
entry=0) at ../sysdeps/unix/sysv/linux/waitpid.c:31
#1  0x00007fecf31fa232 in do_system (line=<optimised out>) at ../sysdeps/posix/system.c:148
#2  0x00007fecf3ea2c03 in TUnixSystem::StackTrace (this=0x2219840) at /opt/root/root/core/unix/src/TUnixSystem.cxx:2419
#3  0x00007fecf3ebfed1 in DefaultErrorHandler (level=<optimised out>, abort_bool=<optimised out>, location=0x7fecea2efcb3 "", msg=0x3593df0 "fHasMultipleVarDim[code] violated at line 509 of `/opt/root/root/tree/treeplayer/src/TTreeFormula.cxx'") at /opt/root/root/core/base/src/TError.cxx:192
#4  0x00007fecf3ebf926 in ErrorHandler(Int_t, const char *, const char *, typedef __va_list_tag __va_list_tag *) (level=level
entry=6000, location=location
entry=0x7fecea2efcb3 "", fmt=0x7fecf4257e08 "%s violated at line %d of `%s'", ap=ap
entry=0x7ffd3dc971d8) at /opt/root/root/core/base/src/TError.cxx:247
#5  0x00007fecf3ebfd72 in Fatal (location=location
entry=0x7fecea2efcb3 "", fmt=<optimised out>) at /opt/root/root/core/base/src/TError.cxx:343
#6  0x00007fecea2a48b6 in TTreeFormula::RegisterDimensions (this=this
entry=0x3586190, code=code
entry=0, leafinfo=leafinfo
entry=0x36313e0, useCollectionObject=<optimised out>) at /opt/root/root/tree/treeplayer/src/TTreeFormula.cxx:509
#7  0x00007fecea2b2b0b in TTreeFormula::ParseWithLeaf (this=this
entry=0x3586190, leaf=0x356f380, subExpression=<optimised out>, final=<optimised out>, paran_level=0, castqueue=..., useLeafCollectionObject=false, fullExpression=0x7ffd3dc98c89 "evt.avInt.") at /opt/root/root/tree/treeplayer/src/TTreeFormula.cxx:1918
#8  0x00007fecea2b93d8 in TTreeFormula::DefinedVariable (this=0x3586190, name=..., action=<optimised out>) at /opt/root/root/tree/treeplayer/src/TTreeFormula.cxx:2937
#9  0x00007feceeee70db in TFormula::Analyze (this=0x3586190, schain=0x7ffd3dc990a9 "evt.avInt.", err=
0x7ffd3dc9904c: 0, offset=0) at /opt/root/root/hist/hist/src/TFormula.cxx:1336
#10 0x00007feceeef01bd in TFormula::Compile (this=0x3586190, expression=<optimised out>) at /opt/root/root/hist/hist/src/TFormula.cxx:2315
#11 0x00007fecea2b035e in TTreeFormula::Init (this=0x3586190, name=0x3585ec0 "Var1", expression=0x35d2719 "evt.avInt.") at /opt/root/root/tree/treeplayer/src/TTreeFormula.cxx:210
#12 0x00007fecea2b08dd in TTreeFormula::TTreeFormula (this=0x3586190, name=0x3585ec0 "Var1", expression=0x35d2719 "evt.avInt.", tree=<optimised out>) at /opt/root/root/tree/treeplayer/src/TTreeFormula.cxx:164
#13 0x00007fecea2c8094 in TSelectorDraw::CompileVariables (this=0x357faf0, varexp=<optimised out>, selection=<optimised out>) at /opt/root/root/tree/treeplayer/src/TSelectorDraw.cxx:999
#14 0x00007fecea2cb0f3 in TSelectorDraw::Begin (this=0x357faf0, tree=<optimised out>) at /opt/root/root/tree/treeplayer/src/TSelectorDraw.cxx:481
#15 0x00007fecea2d0894 in TTreePlayer::Process (this=0x357fa10, selector=0x357faf0, option=0x2ed2019 "", nentries=1, firstentry=0) at /opt/root/root/tree/treeplayer/src/TTreePlayer.cxx:2117
#16 0x00007fecea2d102b in TTreePlayer::DrawSelect (this=0x357fa10, varexp0=<optimised out>, selection=0x7fecef8afdbf "", option=0x2ed2019 "", nentries=1000000000, firstentry=0) at /opt/root/root/tree/treeplayer/src/TTreePlayer.cxx:409
#17 0x00007fecef8618e8 in TVirtualBranchBrowsable::Browse (this=<optimised out>, b=0x27c4e50) at /opt/root/root/tree/tree/src/TBranchBrowsable.cxx:114
#18 0x00007fecec7d2d3d in TGFileBrowser::DoubleClicked (this=0x2ed1010, item=item
entry=0x3571300) at /opt/root/root/gui/gui/src/TGFileBrowser.cxx:1329
#19 0x00007fecec534ea5 in G__G__Gui3_422_0_23 (result7=0x2fab160, funcname=<optimised out>, libp=<optimised out>, hash=<optimised out>) at /opt/root/5.34.36/gui/gui/G__Gui3.cxx:20668
#20 0x00007fecf1f7f03b in Cint::G__CallFunc::Execute (this=0x2fab150, pobject=<optimised out>) at /opt/root/root/cint/cint/src/CallFunc.cxx:440
#21 0x00007fecf3e8c32c in Exec (pobject=<optimised out>, this=<optimised out>) at /opt/root/5.34.36/include/CallFunc.h:100
#22 TCint::CallFunc_Exec (this=<optimised out>, func=<optimised out>, address=<optimised out>) at /opt/root/root/core/meta/src/TCint.cxx:2621
#23 0x00007fecf3ebc1e3 in ExecuteMethod (nparam=2, paramArr=0x7ffd3dc9a310, object=0x2ed1010, this=0x2fab0a0) at /opt/root/root/core/base/src/TQConnection.cxx:404
#24 TQConnection::ExecuteMethod (this=this
entry=0x2faaf80, params=params
entry=0x7ffd3dc9a310, nparam=2) at /opt/root/root/core/base/src/TQConnection.cxx:687
#25 0x00007fecf3f26ed2 in TQObject::Emit (this=0x2f84360, signal_name=signal_name
entry=0x7fecec8bcf10 "DoubleClicked(TGListTreeItem*,Int_t)", paramArr=paramArr
entry=0x7ffd3dc9a310) at /opt/root/root/core/base/src/TQObject.cxx:947
#26 0x00007fecec871c13 in TGListTree::DoubleClicked (this=<optimised out>, entry=<optimised out>, btn=<optimised out>) at /opt/root/root/gui/gui/src/TGListTree.cxx:1165
#27 0x00007fecec874d27 in TGListTree::HandleDoubleClick (this=0x2f84310, event=0x7ffd3dc9a400) at /opt/root/root/gui/gui/src/TGListTree.cxx:689
#28 0x00007fecec7f899b in TGFrame::HandleEvent (this=0x2f84310, event=0x7ffd3dc9a400) at /opt/root/root/gui/gui/src/TGFrame.cxx:496
#29 0x00007fecec7870a8 in TGClient::HandleEvent (this=0x2c92230, event=0x7ffd3dc9a400) at /opt/root/root/gui/gui/src/TGClient.cxx:813
#30 0x00007fecec78735d in TGClient::ProcessOneEvent (this=this
entry=0x2c92230) at /opt/root/root/gui/gui/src/TGClient.cxx:623
#31 0x00007fecec7873bd in TGClient::HandleInput (this=0x2c92230) at /opt/root/root/gui/gui/src/TGClient.cxx:670
#32 0x00007fecf3ea4b78 in TUnixSystem::DispatchOneEvent (this=0x2219840, pendingOnly=<optimised out>) at /opt/root/root/core/unix/src/TUnixSystem.cxx:1093
#33 0x00007fecf3ed9416 in TSystem::InnerLoop (this=0x2219840) at /opt/root/root/core/base/src/TSystem.cxx:410
#34 0x00007fecf3eda020 in TSystem::Run (this=0x2219840) at /opt/root/root/core/base/src/TSystem.cxx:360
#35 0x00007fecf3ec08af in TApplication::Run (this=this
entry=0x23998e0, retrn=retrn
entry=false) at /opt/root/root/core/base/src/TApplication.cxx:1126
#36 0x00007fecf3aaa98e in TRint::Run (this=0x23998e0, retrn=<optimised out>) at /opt/root/root/core/rint/src/TRint.cxx:454
#37 0x0000000000400fec in main (argc=1, argv=0x7ffd3dc9c7a8) at /opt/root/root/main/src/rmain.cxx:29

In case you have some comment I would be pleased if you can share it! :slight_smile:

Cheers,
Vito.

Hi Vito,

For now consider using a vector<vector> instead.

Cheers,
Philippe.

Dear Philippe,

thank you for your answer. So as I was supposing root cannot handle this point? However the solution of a double std vector cannot fit in my structure, I have no power on how the data are organised.

Thank you again for your answer,
Vito.

There seems to be a bug/deficiency in TTreeFormula in your use case (Could you report it to JIRA with a running reproducer?).

You can write and read file with your original construct. To read it as is you will need to use other means (than TTree::Draw) to look at the data, for example TTree::MakeSelector.

Cheers,
Philippe.