Dictionary generation for std::unique_ptr<> Error Root 6.12.07


_ROOT Version: 6.12.07 with CMS patches
Platform: SL6/SL7
Compiler: gcc 7


Changing std::auto_ptr to std::unique_ptr in class_def.xml gives this error message:
Error: It is not necessary to explicitly select class unique_ptr<gen::PdfInfo,default_deletegen::PdfInfo >. I/O is supported for it transparently.

CMS PR producing error

Removing std::unique_ptr from classes_def.xml results in error when reading back root file which makes use of dictionary generated without std::unique_ptr:

Log from unit test:
https://cmssdt.cern.ch/SDT/jenkins-artifacts/pull-request-integration/PR-24565/30469/unitTests.log

----- Begin Fatal Exception 18-Sep-2018 08:14:48 CEST----------------------- An exception of category ‘DictionaryNotFound’ occurred while [0] Constructing the EventProcessor [1] Calling ProductRegistry::initializeLookupTables Exception Message: No data dictionary found for the following classes: __uniq_ptr_impl<gen::PdfInfo,default_delete<gen::PdfInfo> > default_delete<gen::PdfInfo> tuple<gen::PdfInfo*,default_delete<gen::PdfInfo> > unique_ptr<gen::PdfInfo,default_delete<gen::PdfInfo> > Most likely each dictionary was never generated, but it may be that it was generated in the wrong package. Please add (or move) the specification ‘<class name=“whatever”/>’ to the appropriate classes_def.xml file along with any other information needed there. For example, if this class has any transient members, you need to specify them in classes_def.xml. Also include the class header in classes.h A type listed above might or might not be the same as a type stored in the Event (or Lumi or Run). Instead it might be the type of a data member, base class, wrapped type, or other object needed by a stored type. Below is some additional information which lists the stored types associated with the types whose dictionaries were not found:

Hi Patrick,

I propose to get rid of the CMSSW layer to better figure out the problem.
How is the class you are trying to persistify done? In principle, if you have a unique_ptr as a data member, the dictionary which is necessary is the one for T since ROOT treats unique_ptr and T* the same way.

Cheers,
Danilo


namespace gen {
   struct PdfInfo {
      std::pair<int, int>     id;
      std::pair<double, double>  x;
      std::pair<double, double>  xPDF;
      double            scalePDF;
   };
}

class GenEventInfoProduct {
   typedef gen::PdfInfo PDF;
   std::unique_ptr<PDF> pdf_;
}

classes.h

namespace SimDataFormats_GeneratorProducts {
   struct dictionary {
      edm::Wrapper<GenEventInfoProduct> wgeneventinfo;
   }
}

classes_def.xml

 <class name="GenEventInfoProduct" ClassVersion="12">
  <version ClassVersion="12" checksum="4234939286"/>
 </class>

The error message in the unit test is coming from CMS code. We will try to figure out why
initializeLookupTables() is trying to find a dictionary for std::unique_ptr;

Hi Patrick,

on my side, I built a simple reproducer which seems to work as expected. It needs root and 3 files*.

Does it work for the ROOT associated to the CMSSW build you are using?

Cheers,
D

classes.h

#include <memory>

namespace gen {
   struct PdfInfo {
      std::pair<int, int>     id;
      std::pair<double, double>  x;
      std::pair<double, double>  xPDF;
      double            scalePDF;
   };
}

class GenEventInfoProduct {
   public: // added for the example
   typedef gen::PdfInfo PDF;
   std::unique_ptr<PDF> pdf_;
};

classes.xml

<rootdict>
   <class name="gen::PdfInfo" />
   <class name="GenEventInfoProduct" />
</rootdict>

test.C

auto filename = "out.root";
// auto filename = "out.xml"; // Change to this one to produce an xml output file and easily read it

void printGenInfoProduct(const GenEventInfoProduct &g)
{
   auto &id = g.pdf_->id;
   auto &x = g.pdf_->x;
   auto &xPDF = g.pdf_->xPDF;
   auto &scalePDF = g.pdf_->scalePDF;
   std::cout << "id = (" << id.first << ", " << id.second << ")\n"
             << "x = (" << x.first << ", " << x.second << ")\n"
             << "xPDF = (" << xPDF.first << ", " << xPDF.second << ")\n"
             << "scalePDF = " << scalePDF << '\n';
}

void write()
{
   std::unique_ptr<TFile> f (TFile::Open(filename, "RECREATE"));

   GenEventInfoProduct myGenEventInfoProduct;

   // For the sake of this example
   myGenEventInfoProduct.pdf_.reset(new gen::PdfInfo());
   myGenEventInfoProduct.pdf_->id = std::make_pair(2,3);
   myGenEventInfoProduct.pdf_->x = std::make_pair(2.,3.);
   myGenEventInfoProduct.pdf_->xPDF = std::make_pair(4.,6.);
   myGenEventInfoProduct.pdf_->scalePDF = 42.;

   std::cout << "Writing \n";
   printGenInfoProduct(myGenEventInfoProduct);

   f->WriteObject(&myGenEventInfoProduct, "myGenEventInfoProduct");
   f->Close();
}

void read()
{
   std::unique_ptr<TFile> f (TFile::Open("out.root"));
   GenEventInfoProduct *myGenEventInfoProductPtr;
   f->GetObject("myGenEventInfoProduct", myGenEventInfoProductPtr);

   std::cout << "Reading \n";
   printGenInfoProduct(*myGenEventInfoProductPtr);

   f->Close();
}

void test()
{
   write();
   read();
}

The following files reproduces the error we are getting:

classes.h

#include <memory>
#include <iostream>

struct PdfInfo {
	std::pair<int, int>		id;
	std::pair<double, double>	x;
	std::pair<double, double>	xPDF;
	double				scalePDF;
};

class LHEEventProduct {
  public:
	typedef PdfInfo PDF;

	class const_iterator {
	    public:
		typedef std::forward_iterator_tag	iterator_category;
		typedef std::string			value_type;
		typedef std::ptrdiff_t			difference_type;
		typedef std::string			*pointer;
		typedef std::string			&reference;

		const_iterator() : line(npos) {}
		~const_iterator() {}

		inline bool operator == (const const_iterator &other) const
		{ return line == other.line; }
		inline bool operator != (const const_iterator &other) const
		{ return !operator == (other); }

		inline const_iterator &operator ++ ()
		{ next(); return *this; }
		inline const_iterator operator ++ (int dummy)
		{ const_iterator orig = *this; next(); return orig; }

		const std::string &operator * () const { return tmp; }
		const std::string *operator -> () const { return &tmp; }

	    private:
		friend class LHEEventProduct;

		void next();

		const LHEEventProduct	*event;
		unsigned int		line;
		std::string		tmp;

		static const unsigned int npos = 99999;
	};

	const_iterator begin() const;
	inline const_iterator end() const { return const_iterator(); }
	std::unique_ptr<PDF>		pdf_;
};

classes_def.xml

<rootdict>
   <class name="gen::PdfInfo" />
   <class name="LHEEventProduct" />
</rootdict>

test.C

#include "classes.h"
auto filename = "out.root";
//auto filename = "out.xml"; // Change to this one to produce an xml output file and easily read it


void checkClassDictionaries(std::vector<std::string>& missingDictionaries,
                         std::type_info const& typeinfo) {

    TClass* tClass = TClass::GetClass(typeinfo);
    bool result = true;

    THashTable hashTable;
    bool recursive = true;
    tClass->GetMissingDictionaries(hashTable, recursive);

    for(auto const& item : hashTable) {
      TClass const* cl = static_cast<TClass const*>(item);
      std::cout << "missing dictionary for " << cl->GetName() << "\n";
      missingDictionaries.emplace_back(cl->GetName());
      result = false;
    }
    return result;
  }




void printGenInfoProduct(const LHEEventProduct &g)
{
   auto &id = g.pdf_->id;
   auto &x = g.pdf_->x;
   auto &xPDF = g.pdf_->xPDF;
   auto &scalePDF = g.pdf_->scalePDF;
   std::cout << "id = (" << id.first << ", " << id.second << ")\n"
             << "x = (" << x.first << ", " << x.second << ")\n"
             << "xPDF = (" << xPDF.first << ", " << xPDF.second << ")\n"
             << "scalePDF = " << scalePDF << '\n';
}

void write()
{
   std::unique_ptr<TFile> f (TFile::Open(filename, "RECREATE"));

   LHEEventProduct myGenEventInfoProduct;

   // For the sake of this example
   myGenEventInfoProduct.pdf_.reset(new PdfInfo());
   myGenEventInfoProduct.pdf_->id = std::make_pair(2,3);
   myGenEventInfoProduct.pdf_->x = std::make_pair(2.,3.);
   myGenEventInfoProduct.pdf_->xPDF = std::make_pair(4.,6.);
   myGenEventInfoProduct.pdf_->scalePDF = 42.;

   std::cout << "Writing \n";
   printGenInfoProduct(myGenEventInfoProduct);

   f->WriteObject(&myGenEventInfoProduct, "myGenEventInfoProduct");
   f->Close();
}

void read()
{
   std::unique_ptr<TFile> f (TFile::Open("out.root"));
   LHEEventProduct *myGenEventInfoProductPtr;
   f->GetObject("myGenEventInfoProduct", myGenEventInfoProductPtr);
   std::vector<std::string> missingDicts;
   checkClassDictionaries(missingDicts, typeid(*myGenEventInfoProductPtr));

   std::cout << "Reading \n";
   printGenInfoProduct(*myGenEventInfoProductPtr);

   f->Close();
}

void test()
{
   write();
   read();
}

output

 root test.C        
   ------------------------------------------------------------
  | Welcome to ROOT 6.12/07                http://root.cern.ch |
  |                               (c) 1995-2017, The ROOT Team |
  | Built for linuxx8664gcc                                    |
  | From tag , 9 February 2018                                 |
  | Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
   ------------------------------------------------------------

root [0] 
Processing test.C...
Writing 
id = (2, 3)
x = (2, 3)
xPDF = (4, 6)
scalePDF = 42
Error in <TStreamerInfo::Build>: LHEEventProduct: PdfInfo has no streamer or dictionary, data member pdf_ will not be saved
missing dictionary for __uniq_ptr_impl<PdfInfo,default_delete<PdfInfo> >
missing dictionary for LHEEventProduct
missing dictionary for PdfInfo
missing dictionary for unique_ptr<PdfInfo,default_delete<PdfInfo> >
missing dictionary for tuple<PdfInfo*,default_delete<PdfInfo> >
missing dictionary for default_delete<PdfInfo>
Reading 
id = (2, 3)
x = (2, 3)
xPDF = (4, 6)
scalePDF = 42

Even with a properly generated and loaded dictionary library the messages about unique_ptr are missing from the THashTable:

root test.C
   ------------------------------------------------------------
  | Welcome to ROOT 6.12/07                http://root.cern.ch |
  |                               (c) 1995-2017, The ROOT Team |
  | Built for linuxx8664gcc                                    |
  | From tag , 9 February 2018                                 |
  | Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
   ------------------------------------------------------------

root [0] 
Processing test.C...
missing dictionary for unique_ptr<gen::PDFInfo,default_delete<gen::PDFInfo> >
missing dictionary for tuple<gen::PDFInfo*,default_delete<gen::PDFInfo> >
missing dictionary for __uniq_ptr_impl<gen::PDFInfo,default_delete<gen::PDFInfo> >
missing dictionary for default_delete<gen::PDFInfo>
Writing 
id = (2, 3)
x = (2, 3)
xPDF = (4, 6)
scalePDF = 42
missing dictionary for unique_ptr<gen::PDFInfo,default_delete<gen::PDFInfo> >
missing dictionary for tuple<gen::PDFInfo*,default_delete<gen::PDFInfo> >
missing dictionary for __uniq_ptr_impl<gen::PDFInfo,default_delete<gen::PDFInfo> >
missing dictionary for default_delete<gen::PDFInfo>
Reading 
id = (2, 3)
x = (2, 3)
xPDF = (4, 6)
scalePDF = 42

Filed a Jira ticket for this
https://sft.its.cern.ch/jira/browse/ROOT-9698?filter=-2

Patrick, the fix has been merged into master and your item will be closed soon.

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