Problem with std::vector<> of custom objects and CMake

Hi all:

I have a “small” problem with a std::vector of a class I defined called Hit (ie std::vector). I created a program compiled with CMake that opens a file that contains a TClonesArray of custom objects called “event”. Each event object contains at the same time a std::vector.

The point is that the “event” class a method (GetHitArray) to retrieve a pointer to the std::vector but It is doing weird things. It just crashes whenever I try to do anything with it (size or loop over it for example). The event class has another method that allows to retrieve one of the Hits inside the vector without any problem. I can also create a std::vector<Hit*>* this is a vector pointer to store Hit pointers to store the address of the hits but a std::vector* crashes as well.

I suspect this has something to do with destructors and copies but I am not that expert.

Here is the puzzle:

Int_t main()
{

    gSystem->Load("libCling.so");
    gSystem->Load("libATTPCReco.so");

    FairRunAna* run = new FairRunAna(); //Forcing a dummy run

    TString workdir = getenv("VMCWORKDIR");
    TString FileNameHead = "output";
    TString FilePath = workdir + "/macro/Unpack_GETDecoder2/";
    TString FileNameTail = ".root";
    TString FileName     = FilePath + FileNameHead + FileNameTail;

    std::cout<<" Opening File : "<<FileName.Data()<<std::endl;
    TFile* file = new TFile(FileName.Data(),"READ");

    TTree* tree = (TTree*) file -> Get("cbmsim");
    Int_t nEvents = tree -> GetEntries();
    std::cout<<" Number of events : "<<nEvents<<std::endl;

    TTreeReader Reader1("cbmsim", file);
    TTreeReaderValue<TClonesArray> eventArray(Reader1, "ATEventH");
    TTreeReaderValue<TClonesArray> houghArray(Reader1, "ATHough");

          while (Reader1.Next()) {


              ATEvent* event = (ATEvent*) eventArray->At(0);
              Int_t nHits = event->GetNumHits();
              std::vector<ATHit>* hitArray = event->GetHitArray(); //Not working!              
              std::vector<ATHit*>* hitbuff = new std::vector<ATHit*>; // Working!


                    for(Int_t iHit=0; iHit<nHits; iHit++){
                      ATHit hit = event->GetHit(iHit);
                      TVector3 hitPos = hit.GetPosition();
                      hitbuff->push_back(&hit);


                    }

              //std::cout<<hitbuff->size()<<std::endl;

              ATHoughSpace* fHoughSpaceCircle  = dynamic_cast<ATHoughSpaceCircle*> (houghArray->At(0));
              //if(!fHoughSpaceCircle) std::cout<<" Warning : Failed casting "<<std::endl;
              //fHoughSpaceCircle->GetXCenter();


          }

  //#pragma omp parallel for ordered schedule(dynamic,1)
  //for(Int_t i=0;i<100;i++)std::cout<<" Hello ATTPCer! "<<std::endl;
   return 0;

}

And the CMakeLists.txt which is a MESS.

Thank you very much in advance!

Y.
CMakeLists.txt (1.15 KB)

Hi,

Please do not load libCling. You should link against libRIO etc - that should be all you need. libCling is internal, and gets loaded through other mechanisms.

Do you have a dictionary for std::vector that is loaded for the program you show (i.e. not just while writing the file but also during reading)? I don’t see the dictionary being used anywhere in your CMake file (but I still have a hard time reading them, so it might just be me.)

Cheers, Axel.

Hello again:

Thank you very much for the quick answer. It is probably a question of dictionary but to be honest I do not know how to proceed. I have a dictionary for the library that contains the ATHit class called G__ATTPCRecoDict.cxx and G__ATTPCRecoDict_rdict.pcm but not loaded obviolusly. In the CMakeLists.txt the only thing I have for the dictionary is the line ROOT_GENERATE_DICTIONARY(G__MCSrc MCSrc.hh LINKDEF MCSrcLinkDef.h)

So I am afraid that this is a question of not knowing how to do it :slight_smile:

Thank you very much again!

Y.

Hola Francesc,
It is not easy to fix the building of the dictionary without having all the code nd the rest of the system. I have modified and simplified the CMakeLists.txt file (attached). It is clearly not compete because it requires additional definition of variables such as ATTPCROOTPATH, FAIRROOT_LIBRARY_DIR. Use it as an example that you will need to complete.

The CMake function ROOT_GENERATE_DICTIONARY() generates a source file (G__MCSrc.cxx) that you can add into a library (MCSrc), which then you will be able to load (gSystem->Load(“libMCSrc.so”):wink: or use it to build an executable (MCExe).
CMakeLists.txt (1.47 KB)

Hola!

First of all thank you very much for the help! this is something I really need to fix.

Just to clarify (because I explain things in a very bad way to be honest), there is another CMakeLists.txt on the upper folder that contains this code that defines the environment (FAIRROOT and ATTPCROOT). You are right this is difficult to debug because it belongs to a big project with a lot of libraries and each library has an associated dictionary of course. Maybe I am wrong but I understand that by loading (and linking of course) the library for which we already created a dictionary (gSystem->Load(“libATTPCReco.so”):wink: and including the headers, the program “should” understand whats inside the root file I am trying to read, right?

Anyway let me try from the scratch with the CMakeLists.txt you attached and I will report what I find.

Gracies! :slight_smile:

Hi again

I am back with more information. I implemented a stand alone version of what I want to do, this is I tried to compile with CMake a program that uses ROOT libraries and libraries I made myself usign other libraries based on root (namely Fairroot package from GSI).

Lets go step by step. I used the CMakeList.txt (attachment) that Mato pasted here with some modifications to include paths and to avoid linking cling. For some reason I had to include every library one by one. The thing compiles the library and the exe. If I only use root libraries, the program works perfectly.

Here is the new code that works with the “troublemakers” commented (essentially the same as before):


#include "MCSrc.hh"
#include <ios>
#include <iostream>
#include <istream>
#include <limits>
#include <map>
#include <vector>

#include "TClonesArray.h"
#include "TString.h"
#include "TFile.h"
#include "TTree.h"
#include "TTreeReader.h"
#include "TTreePlayer.h"
#include "TTreeReaderValue.h"
#include "TSystem.h"
#include "TH1F.h"
#include "TCanvas.h"

#include "ATEvent.hh"
#include "ATPad.hh"
#include "ATHit.hh"
#include "ATHoughSpace.hh"
#include "ATHoughSpaceLine.hh"
#include "ATHoughSpaceCircle.hh"

#include "FairRootManager.h"
#include "FairLogger.h"
#include "FairRun.h"
#include "FairRunAna.h"

Int_t main()
{

    gSystem->Load("libATTPCReco.so");

    FairRunAna* run = new FairRunAna(); //Forcing a dummy run

    TString workdir = getenv("VMCWORKDIR");
    TString FileNameHead = "output";
    TString FilePath = workdir + "/macro/Unpack_GETDecoder2/";
    TString FileNameTail = ".root";
    TString FileName     = FilePath + FileNameHead + FileNameTail;

    std::cout<<" Opening File : "<<FileName.Data()<<std::endl;
    TFile* file = new TFile(FileName.Data(),"READ");

    TTree* tree = (TTree*) file -> Get("cbmsim");
    Int_t nEvents = tree -> GetEntries();
    std::cout<<" Number of events : "<<nEvents<<std::endl;

    TTreeReader Reader1("cbmsim", file);
    TTreeReaderValue<TClonesArray> eventArray(Reader1, "ATEventH");
    TTreeReaderValue<TClonesArray> houghArray(Reader1, "ATHough");

          while (Reader1.Next()) {


              ATEvent* event = (ATEvent*) eventArray->At(0);
              Int_t nHits = event->GetNumHits();
              std::vector<ATHit>* hitArray = event->GetHitArray(); //Not working!
              //hitArray->size();

              std::vector<ATHit*>* hitbuff = new std::vector<ATHit*>; // Working!

              //std::vector<ATEvent*> test;
              //test.push_back(event);

                    for(Int_t iHit=0; iHit<nHits; iHit++){
                      ATHit hit = event->GetHit(iHit);
                      TVector3 hitPos = hit.GetPosition();
                      hitbuff->push_back(&hit);


                    }

              //std::cout<<hitbuff->size()<<std::endl;

              //ATHoughSpace* fHoughSpaceCircle  = dynamic_cast<ATHoughSpaceCircle*> (houghArray->At(0));
              //if(!fHoughSpaceCircle) std::cout<<" Warning : Failed casting "<<std::endl;
              //fHoughSpaceCircle->GetXCenter();


          }

  //#pragma omp parallel for ordered schedule(dynamic,1)
  //for(Int_t i=0;i<100;i++)std::cout<<" Hello ATTPCer! "<<std::endl;
   return 0;

}

Now, I implemented few objects and pointers of my ATTPCReco library. In the code you can see that from the file called output.root I can retrieve two TCloneArrays containing two different objects (ATEventH and ATHough). I can read the tree and get the entries. Moreover you can see that I can create a pointer “event” which is a class contained in the ATTPCReco library. I can get the number of hits that every event contains by using a member of event (ATHit hit = event->GetHit(iHit)) and see what each hit contains.

I can also compile the line std::vector* hitArray = event->GetHitArray(); //Not working! but when I want to use it with for example hitArray->size(); it crashes (memory problems?). More things, the library also contains a class called ATHoughSpace (in this case stored in the ATHough TClonesArray) and I can retrieve them but when I try to use any of the members of ATHoughSpaceCircle, it complains when linking:

 error: ‘class ATHoughSpace’ has no member named ‘GetXCenter’
               fHoughSpaceCircle->GetXCenter();

So this is essentially the big picture of the problem. I cannot make my custom library work in a compiled program. Do I need to link the ATTPCReco library somehow?

Again thank you very much before hand!

Y.
CMakeLists.txt (2.3 KB)

Hola, I am more confused now. It seems tat you are mixing compilation problems ( ATHoughSpace’ has no member named ‘GetXCenter’), with linking problems (additional libraries that you need to use), with runtime problems (the actual data file may not contain what you think it contains).
Can you make your input file ( output.root !) available some where such that we can have a look of what it actually contains.

Bon dia!

You know what? I figured out were the problem was while I was trying to explain you few things. Theres no need for a root file because I solved it thanks to your help. Long story short: headers were outdated.

So, I would like to ask the moderators to tag this post as solved and keep the CMakeLists.txt you did as another example, which is always helpful for beginners like me.

Moltes gracies! :smiley: