Std::map in struct

Hi,
I’m trying to declare a map in a struct, but I’m having some problems with the syntax.

This is what I’m trying:

gROOT.ProcessLine('struct EtaData {\ int var1;\ float var2;\ std.map(unsigned int, float) stripsMap;\ };')

and I get

I’ve also tried (with same result) :

Any help please ?

from ROOT import * gROOT.ProcessLine("#include <map>") gROOT.ProcessLine("struct EtaData {\ std::map<unsigned int, float> stripsMap;\ float var2;\ int var1;\ };")
And move to ROOT6. Really. With 5, need dictionary and template instantiation on top of above.

-Dom

Thanks for your reply Dominique.

Switching to ROOT6 for me means to work with the new version for the externals, which also includes Python 3 and this seems to cause some problems to my script which I believe are not related to this std::map question.

However when I tried to use the lines of code in your last post with ROOT5, I didn’t get any warning or error messages but the map in the ROOT file wasn’t being filled (or at least that’s what it seems when looking with TBrowser). Any explanation for why this could happened ?

ROOT6 does not require p3.

Probably phase of moon. More intelligent response needs detailed code of what you do.

-Dom

Hi Dominique,

I’ve tested my code and it’s really adding line the lines of code you wrote in your post that causes this (using ROOT6 and python3):

*** glibc detected *** python3: malloc(): memory corruption: 0x00000000054639b0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x75f4e)[0x7f082ed25f4e]
/lib64/libc.so.6(+0x7a3d0)[0x7f082ed2a3d0]
/lib64/libc.so.6(__libc_malloc+0x65)[0x7f082ed2ab55]
/cvmfs/belle.cern.ch/sl6/externals/v01-01-00/Linux_x86_64/common/lib64/libpython3.5.so.1.0(+0xb2e98)[0x7f0830152e98]
/cvmfs/belle.cern.ch/sl6/externals/v01-01-00/Linux_x86_64/common/lib64/libpython3.5.so.1.0(PyDict_SetItem+0x362)[0x7f0830154522]
/cvmfs/belle.cern.ch/sl6/externals/v01-01-00/Linux_x86_64/common/lib64/libpython3.5.so.1.0(PyEval_EvalFrameEx+0x4ee2)[0x7f08301ef3b2]
/cvmfs/belle.cern.ch/sl6/externals/v01-01-00/Linux_x86_64/common/lib64/libpython3.5.so.1.0(+0x153ca4)[0x7f08301f3ca4]
/cvmfs/belle.cern.ch/sl6/externals/v01-01-00/Linux_x86_64/common/lib64/libpython3.5.so.1.0(PyEval_EvalCodeEx+0x23)[0x7f08301f3d83]
/cvmfs/belle.cern.ch/sl6/externals/v01-01-00/Linux_x86_64/common/lib64/libpython3.5.so.1.0(PyEval_EvalCode+0x1b)[0x7f08301f3dab]
/cvmfs/belle.cern.ch/sl6/externals/v01-01-00/Linux_x86_64/common/lib64/libpython3.5.so.1.0(PyRun_FileExFlags+0xb2)[0x7f083021c692]
/cvmfs/belle.cern.ch/sl6/externals/v01-01-00/Linux_x86_64/common/lib64/libboost_python.so.1.59.0(_ZN5boost6python9exec_fileENS0_3strENS0_3api6objectES3_+0x85)[0x7f08307ee705]
basf2[0x40adfb]
basf2[0x40d59e]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x7f082ecced5d]
basf2[0x40a639]

Excepting neither ROOT, PyROOT, or Python (2/3) uses boost … Argue problem caused by something else.

-Dom

Given that working with ROOT6 was giving some unexplained problems (like the one you mentioned in your last post Dominique),
I went back to ROOT5 and noticed that these dictionaries

AutoDict_binary_function_unsigned_int_unsigned_int_bool_.cxx
AutoDict_map_unsigned_int_float_less_unsigned_int__allocator_pair_const_unsigned_int_float_____.cxx

are automatically generated, however I get

TClass::TClass:0: RuntimeWarning: no dictionary for class pair<unsigned int,float> is available

which doesn’t cause my code to crash but the map doesn’t get filled (I didn’t see this line before).

So I tried to add:

gInterpreter.GenerateDictionary("pair<unsigned int, float>","utility");

but it is not working (still dictionary for pair is missing).

As said, can’t help unless post actual code of what your doing.

My setup, all work fine (5):[code]>>> from ROOT import *

p = std.pair(‘unsigned int’, ‘float’)(1, 2.)
Traceback (most recent call last):
File “”, line 1, in
File “/home/wlav/rootdev/root/lib/ROOT.py”, line 197, in call
result = _root.MakeRootTemplateClass( *newargs )
TypeError: requested class ‘ROOT::pair<unsigned int,float>’ does not exist

gInterpreter.GenerateDictionary(“pair<unsigned int, float>”,“utility”)
0

p = std.pair(‘unsigned int’, ‘float’)(1, 2.)
p.first, p.second
(1L, 2.0)

[/code]
et of course (6) easier b/c no need GenerateDictionary:[code]>>> from ROOT import *

p = std.pair(‘unsigned int’, ‘float’)(1, 2.)
p.first, p.second
(1L, 2.0)

[/code]
W/o code, only think could work is “rm -rf AutoDict*” and try again.

-Dom

Yes, removing the dictionary and trying again was the easy fix needed, thanks !

In the same pyroot module I want to fill the map in the struct by doing:

stripsMap = something.getMap()

where again

gROOT.ProcessLine("struct EtaData {\
 std::map<unsigned int, float> stripsMap;\
};")

I get a segmentation fault when that line is processed, does this mean that getMap() is just not providing a map or there could be something wrong in that line ? (It’s a bit hard to send you the code I’m using because it uses a whole framework).

Fine, but can at least see need definition of ‘getMap()’, ‘something’, and ‘stripsMap’ in context?

Guessing getMap() does:void Something::getMap() { int *i = 0; *i = 134; }
Guess maybe wrong, but fit all information you give.

-Dom

Sure. They all come from different parts of the something class:

class something: public RelationsObject {
 public:

something():
m_var1(0), m_var2(0),
m_stripsMap()
  {}

something(
double var1, double var2
std::map<unsigned int, float> StripsMap):
m_var1(var1), m_var2(ivar2),
m_stripsMap(StripsMap)
    {}

All code pass all map by value. Inefficient and easy to SIGSEGV. Return from getStripsMap() is temp. Should not pass to SetBranchAddress() etc., as will fill temp map, not m_stripsMap. Need to make sure to keep alive with python reference until end of use.

Okay, for good case, make example work. One, toto.h:[code]#include
#include

class RelationsObject { };

class something : RelationsObject {
public:
something(): m_var1(0), m_var2(0), m_stripsMap() {}
something( double var1, double var2,
std::map<unsigned int, float> StripsMap):
m_var1(var1), m_var2(var2),
m_stripsMap(StripsMap)
{}

const std::map<unsigned int, float> getStripsMap() const {
return m_stripsMap;}

double m_var1, m_var2;
std::map<unsigned int, float> m_stripsMap;
};[/code]
And two, toto.py:[code]from ROOT import *
gInterpreter.GenerateDictionary(“map<unsigned int, float>”,“map”);
gInterpreter.GenerateDictionary(“pair<unsigned int, float>”,“utility”);
gROOT.LoadMacro(“toto.h+”)

gROOT.ProcessLine(“struct EtaData {
std::map<unsigned int, float> stripsMap;
};”)

m = std.map(‘unsigned int, float’)()
for k, v in zip(xrange(10), xrange(10)):
m[k] = 3.14*v

s = something(0., 1., m)
e = EtaData()
e.stripsMap = s.getStripsMap()[/code]
with run like:$ python toto.pyand then SIGSGEV, yes? See, make reproducer is easy.

And now have trace, yes? Trace say broken memory of “e.stripsMap” (EtaData default ctor not generated and can not put in ProcessLine b/c “CINT limitation”). Can see by adding:"struct EtaData {\ std::map<unsigned int, float> stripsMap;\ };to toto.h instead of ProcessLine(), then all work fine.

CINT no longer developed, need workaround use ACLIC (or use ROOT6, already said that). Example toto2.py have workaround:[code]from ROOT import *
gInterpreter.GenerateDictionary(“map<unsigned int, float>”,“map”);
gInterpreter.GenerateDictionary(“pair<unsigned int, float>”,“utility”);
gROOT.LoadMacro(“toto.h+”)

import os
fn = “cint_bricolage.C"
try:
f = os.open(fn, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
except OSError:
pass
else:
os.write(f, “””#include
struct EtaData {
std::map<unsigned int, float> stripsMap;
};""")
os.close(f)
gROOT.LoadMacro(fn+’+’)

m = std.map(‘unsigned int, float’)()
for k, v in zip(xrange(10), xrange(10)):
m[k] = 3.14*v

s = something(0., 1., m)
e = EtaData()
e.stripsMap = s.getStripsMap()[/code]
Now no SIGSEGV. Still argue fix all temp creates.

-Dom

Thanks for your help,
but I don’t understand what should cint_bricolage.C be.
It looks like it’s too much of a workaround to extract the map, so I will go for an easier solution.

[quote]but I don’t understand what should cint_bricolage.C be.[/quote]it contains the code that you were passing to ProcessLine in the first post so that it can be compiled by ACLiC (and thus have the complete, correct information).

Cheers,
Philippe.