Home | News | Documentation | Download

Deep copy pointers when writing an object of a class added to Root


#1

Imagine a class added to Root

class classA: public TNamed
{
public:
  classA();
  unsigned int n;
  unsigned int * p;
  void Do();
  ClassDef(classA, 1)
};

When writing a class object to a root file I would like a deep copy of pointer members (unsigned int *p). When reading the object of a class from a Root file I would like the contents of memory pointed to by the pointers restored.

How can I achieve that? Can you provide a simple example for the case of the unsigned int *p member of classA?


#2

Try

class classA: public TNamed
{
public:
  classA();
  unsigned int n;
  unsigned int * p; ///< [n]
  void Do();
  ClassDef(classA, 1)
};

assuming n is the number of elements in the array point to by p.


#3

That works.
But the inevitable question that will get asked is what if one has used a new[] operator on p and the number of elements is some arbitrary integer?


#4

And how to handle the case of STL containers containing pointers, e.g.
vector<double *> vp;


#5

I forgot to mention that β€˜n’ also need to have its type changed to β€˜int’ (the internal of the I/O currently assume this type).

Well (I assumed that the new[] operator was called but that the argument was stored in β€˜n’), the I/O must have some way of knowing the number of elements that should be stored, having a data member holding this information is the option we are supporting :slight_smile:

And how to handle the case of STL containers containing pointers, e.g. vector<double *> vp;

vector of pointers are only supported when the pointee is a class and points to a single element. For anything else use nested vectors. e.g. vector<vector<double> > vp;

Cheers,
Philippe.


#6

Could you please provide more information how to implement this:


#7
class classA: public TNamed
{
public:
  classA() : n(0), p(nullptr) {}
  ~classA() { delete [] p; }
  int n;
  unsigned int * p; ///< [n]
  void Do(int numberOfElements, ..... ) {
      p = new unsigned int[numberOfElements];
      n = numberOfElements;
      for(int i = 0; i < n ; ++i) {
         p[i] = .....;
       }
  }
  ClassDef(classA, 1)
};

#8

I assume these classes must be added to Root?


#9

I assume these classes must be added to Root?

If you want to store instances of a class in a ROOT file, that class need to have a ROOT dictionary. The sole expection is STL containers (themselves, not their) content that are stored as part of a class that has a dictionary. In this case, the dictionary for the STL collection is made automatically. For example for

class A {
   std::vector<B> fB;
   std::vector<C*> fC;
   std::vector<std::vector<double> > fD;
};

You need to explicitly request the dictionary fo A, B and C.

Cheers,
Philippe.


#10

what if I define n as a static member of classA:

class classA: public TNamed
{
public:
  classA() : n(0), p(nullptr) {}
  ~classA() { delete [] p; }
  const static int n;
  unsigned int * p; ///< [n]
  void Do(int numberOfElements, ..... ) {
      p = new unsigned int[numberOfElements];
      n = numberOfElements;
      for(int i = 0; i < n ; ++i) {
         p[i] = .....;
       }
  }
  ClassDef(classA, 1)
};

I suppose classA::n must be separately added to Root. How to do that?


#11

static data member are not stored as part of ROOT file. But if it a const static, then actually you can simply do:

class classA: public TNamed
{
public:
  classA() : n(0), p(nullptr) {}
  ~classA() { delete [] p; }
  constexpr static int n = numberOfElements;
  unsigned int p[n];
  void Do( ..... ) {
      for(int i = 0; i < n ; ++i) {
         p[i] = .....;
       }
  }
  ClassDef(classA, 1)
};

#12

I cannot use ///< [n] if n is declared as a static (non-const) member of classA?


#13

No, because it will not be stored and thus upon reading we wont know the size.


#14

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.