The pointer specified for str is not of a class or type known to ROOT

Hi

I have a C++ code and I am trying to read from a *.dat file and fill a tree/branch with string. My ROOT version is v6.08.02.
It gives this error:
“Error in TTree::Branch: The pointer specified for str is not of a class or type known to ROOT”

The main code is very long, so below is just a briefed version which shows the main part of the code:

include "TFile.h"
include "TTree.h"
include "TSystem.h"
include "iostream"
include "sstream"
include "fstream"
include “vector”

using std::ifstream;
using std::ofstream;
using namespace std;
using std::vector;

string str;
TFile *OutputFile = new TFile(“FILE_NAME”, “RECREATE”);
TTree *Tree_Data_Set = new TTree(“Data_Set”, “Data Set”);
Tree_Data_Set->Branch(“str”, &str);

ifstream indata;
indata.open(“filen_ame.dat”); // opens the file
while ( !indata.eof() ) { // keep reading until end-of-file
indata >> str;
if (indata.eof()) break;
Tree_Data_Set->Fill();
}
indata.close();
OutputFile->Write();
OutputFile->Close();

Any comment would be appreciated, thanks.

I don’t know why it doesn’t work for you - but for me the code works. Could you provide a full example that one can reproduce? (and please use “preformatted text”, otherwise some parts of your code, e.g. the # characters, will be lost)

Full compilable example that works for me - some ROOT 6.09/03 version, compiled with g++ -Wall -Wextra treeString.C $(root-config --cflags --libs):

#include <string>
#include <TTree.h>
#include <TFile.h>

int main() {
    std::string str = "Hello world";
    TFile *OutputFile = new TFile("FILE_NAME.root", "RECREATE");
    TTree *Tree_Data_Set = new TTree("Data_Set", "Data Set");
    Tree_Data_Set->Branch("str", &str);
    Tree_Data_Set->Fill();
    OutputFile->Write();
    delete OutputFile;
}

However, when I open the file and view it in a TBrowser and double-click the str object, I get a Warning/Error even though drawing c_str or size seem to work properly:

Warning in <TStreamerInfo::Build>: reverse_iterator<__gnu_cxx::__normal_iterator<const char*,string> >: base class iterator<random_access_iterator_tag,char,long,const char*,const char&> has no streamer or dictionary it will not be saved
Error in <TClass::BuildRealData>: Inspection for allocator<char> not supported!
Warning in <TStreamerInfo::Build>: allocator<char>: base class __gnu_cxx::new_allocator<char> has no streamer or dictionary it will not be saved

I don’t know if it is supposed to be that way - ROOT experts?

My workarounds:
a) I usually store a C-String instead - always works without any problems unless you have a \0 in your string. So simply do something like:

Char_t cstr[500];
tree->Branch("str", &cstr, "str/C");
(loop) {
    strlcpy(cstr, str.c_str(), sizeof(cstr));
    tree->Fill();
}

b) maybe wrapping the std::string in a struct and adding a dictionary for your string wrapper struct helps? Even though I think it was only required in ancient Root 5.x versions.

General comments about your C++ style:

  • A loop starting with while ( !indata.eof() ) is correct in Pascal (and dialects like Delphi) but almost always wrong or at least bad style in C++. That is because in C++ the eof-bit is only set after you have tried to read past the end of a stream - the check is simply too early in the head of a while loop where you want to know if the NEXT read would fail. Instead simply try to read until reading fails:
    while (indata >> str) {...}
    The result of operator>> (the istream) converts to true iff the operation was successful. So always read a stream using stream >> variable in the while head. The while body will only be executed while reading was successful. That way you can remove the if (indata.eof()) break; from the while body as well.

  • About importing namespaces: if you are using using namespace std;, why do you include the using declarations for std::ifstream/std::ofstream and std::vector as well?

Thanks indeed for the comments…

Regarding my c++ style: you are right and I fixed the "readin’’ command as you suggested. Actually, that was my issue for a long time.

About importing extra libraries: those were my naive try to solve the recent problem suggested on-line which they didn’t work.

Regarding your workaround suggestion: I would rather to keep what I have developed so far. The reason is that the input strings have different sizes and the way you defined it, as a fixed array, doesn’t work on my code, thanks though.
Actually, if you know a way to use vector <Char_t> with variable sizes instead of a fixed array would be very nice. However, I need a way, first, to save the string in to a tree, and then read it from the tree again.

Regarding my main question here, I should say the code runs properly on my own desktop too, but when I want to run it on the cluster it shows that error. The cluster has the same ROOT and c++ compiler version, so I am confused what can be a problem there.

Thanks

Hi,

On the failing node try:

$ root.exe -b -l
root [0] TClass::GetClass("std::string")->IsLoaded()
(bool) true

if it returns anything but ‘true’ then there is something wrong with your installation/setup.

Cheers,
Philippe.

It returns true. My guess is compiler is different, Thanks though.

My guess is compiler is different, Thanks though

I am not sure what you mean … the last thing to try is

TClass::GetClass(typeid(std::string))->IsLoaded()

if that also returns true then the error message you mention should not happen.

Thanks. The second one also returns true.
By compiler I meant maybe the compiler on the cluster, where I am trying to run the code, maybe is different form the one I have on my desktop. The code works properly on my desktop, but not at the cluster.