Call to deleted constructor of 'TTreeReaderValue<T>'

Hi Everyone,

I’m working on some code that requires a couple of TTreeReaderValue<T> Variables to be declared before they’re defined, it works well in ROOT 6.10. But now working with ROOT 6.13 (just built) I found this error all over the place:

error: call to deleted constructor of 'TTreeReaderValue<Int_t>' (aka 'TTreeReaderValue<int>')

and:

note: 'TTreeReaderValue' has been explicitly marked deleted here
   TTreeReaderValue() = delete;

This change was introduced here. Is there any way around it? You can get the same error by trying to declare a variable like:

TTreeReaderValue<Int_t> n

Any suggestion would be appreciated,

All the best,

I will have to re-visit that, thanks for pointing it out. I don’t remember from the top of my head why I deleted the default constructor.

As a workaround you can use unique_ptr<TTreeReaderValue<Int_t>>, and create it (e.g. using std::make_unique from ROOT/RMakeUnique.hxx) when you currently set the tree and branch name.

1 Like

Out of curiosity: what is your use case that you need to default-construct a TTreeReaderValue?

Hi,
isn’t a default-constructed TTreeReaderValue completely useless? It has no setters afaik, so you cannot default-construct it and later make it point to the right TTreeReader and branch.

@amvargash I am curious what the use-case is for default-constructing TTreeReaderValues.
I am not sure what you mean with “variables are declared before they are defined” – in C++ forward declaration of variables is expressed with the extern keyword, but that does not trigger a default construction. If you don’t put extern in front of the declaration that counts as definition.

Hi Everyone,

so you cannot default-construct it and later make it point to the right TTreeReader and branch.

I have some private members in the headers of a class, like:

class MPr {
  
 private :

  TTreeReader fReader;
  
  TTreeReaderValue<Int_t> fn1;
  TTreeReaderValue<Int_t> fn2;
...
}

and then:

MPr::Mpr(/* not the default constructor */) 
: fn(fReader, "P.tr.n1"),
  fn(fReader, "P.tr.n2")
{
   .....
}
....

I think I saw a similar example when using TSelector for TProof but I don’t remember right now where (and I use them here for a different purpose than TProof).

EDIT: The constructor shown is not the default constructor.

And how does this code require a default constructible TTreeReaderValue?

Hi @behrenhoff, as I mentioned initially, you can get the same error by runing:

root[0] TTreeReaderValue<Int_t> n

And then you get:

ROOT_prompt_0:1:25: error: call to deleted constructor of 'TTreeReaderValue<Int_t>' (aka 'TTreeReaderValue<int>')
TTreeReaderValue<Int_t> n
                        ^
$ROOTSYS/include/TTreeReaderValue.h:130:4: note: 'TTreeReaderValue' has been explicitly marked deleted here
   TTreeReaderValue() = delete;

Hi,
I think there are some pieces missing in your explanation:

TTreeReaderValues cannot be default-constructed (anymore), but that is a good thing, because a default-constructed TTreeReaderValue is effectively useless.
On the other hand, your code snippet does not default-construct any TTreeReaderValue (root[0] TTreeReaderValue<Int_t> n does, but that’s not your case).

It would be good to find out what is the exact piece of C++ code that you are compiling that is trying to default-construct a TTreeReaderValue, and why: it’s probably not what you want.

Hi @eguiraud. The error is originated in the default constructor of the class. Look, this is the very first line that it shows when trying to use a Script that uses MPr

MPr.cxx:6:9: error: call to deleted constructor of 'TTreeReaderValue<TTimeStamp>'
MPr::MPr(){
        ^

Alright, so the default ctor of MPr default-constructs some TTreeReaderValues.

Independently of @Axel deciding to reinstate the default ctor or not, default TTreeReaderValues are useless (I guess you never actually use them, as they can do nothing), so you might want to avoid constructing them altogether.
One way to do so is changing the types of your data members from TTreeReaderValue<TTimeStamp> to std::unique_ptr<TTreeReaderValue<TTimeStamp>>, as @Axel suggested above. Or maybe revisit the logic of MPr (what does a default-constructed MPr mean? It certainly is a different object than a non-default-constructed MPr, because it has less capabilities: it will never read any data with a TTreeReaderValue).

Yes, but what is that default constructor good for? You can’t use the object anyway. So why do you need to be able to default-construct MPr - its internal TTreeReaders seem useless in that case.

So maybe it falls back to a SW design question?

(and my prev comment “And how does this code require a default constructible TTreeReaderValue?” was of course a direct answer to the code you were showing - there was no TTreeReaderValue default constructor involved in your snippet)

Actually, the MPr default constructor is doing nothing right now :sweat_smile: So I’ll just remove it. But if I have:

: fn(fReader, "P.tr.n1"),
  fn(fReader, "P.tr.n2")
{
   .....
}
....

Right after, it also solves the problem. If I’m not wrong the default constructor is required somewhere (I’ll check).

I was thinking the lines in the header were related with the error produced, but @eguiraud made me realize the error was coming from another piece of code :yum:.

Thank you guys :love_you_gesture:

Hello there,

I have another question regarding the same topic. When I have different constructors for “Mpr”, I have to use this portion of code:

: fn(fReader, "P.tr.n1"),
  fn(fReader, "P.tr.n2")
{
   .....
}
....
 

(if I don’t use it I get the “call to deleted…”) . I was trying to define a Set method in the same way TDatime use it (https://github.com/root-project/root/blob/f32175eb0b4da1b95180f029efe2064d90c93b0e/core/base/src/TDatime.cxx#L58) in order to avoid writing the same code again and again (just don’t look like the right way to do it) However I can’t use that portion of the code in another member which is not a constructor. Do you know any other way to avoid writing these definitions more than once?

Thank you,

In C++, when the body of constructors is executed, all data members have already been constructed. This means that you cannot construct your TTreeReaderValues inside a Set method that you would call from the ctor body (they have already been constructed, or better you already tried to invoke their deleted default constructor).

What you probably want is delegating constructors, i.e. you probably want to call one constructor from the others to avoid code repetition.

Hope that helps.
Enrico

1 Like

And if that doesn’t help, you could always use a builder.
Caution: I might have read too much “enterprise grade” Java code to come up with this :wink:

1 Like

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