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.

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