[odb-users] Using Custom Container (with template) makes odb crash

Alexis Mestag alexis.mestag at epitech.eu
Sun Dec 15 14:40:04 EST 2013


Hello everyone,

I use ODB for a school C++ project. I need relationships for my persistent
objects, for example, a list of pointers.
ODB recognizes relationships made with list of pointers.
The problem is, in my class, I want to store a POINTER to a list of pointers
to make the relationship, not the list directly.
So far, in order to do that, I created a wrapper to a list, and implemented
the templated odb::access::container_traits class to make ODB recognize my
custom container (as it's explained in the documentation).

For example, I need that :

// Person.hh
class Person
{
  friend class odb::access;

private:
  // ODB will not recognize this since it's a pointer to a list, not
directly the list.
  std::list<Person *>  *_friends;
};

#ifdef ODB_COMPILER
#  pragma db object(Person)
#endif

So I transform the class as followed :

// Person.hh

#include "Friends.hh"

class Person
{
  friend class odb::access;

private:
  Friends  *_friends;
};

#ifdef ODB_COMPILER
#  pragma db object(Person)
#endif

I add this class :

// Friends.hh

class Friends
{
private:
  std::list<Person *>  *_elts;
};

I implement the class odb::access::container_traits<Friends *> in a
Friends-traits.hxx file, create the Friends.options file and add it in the
parameters of the compilation command.
That works well.
The problem of this solution is that I need to recreate a wrapper to a list,
reimplement the odb::access::container_traits<Whatever *> class, recreate a
Whatever.options file and also add it in the command each time I make a
relationship.

To solve this problem, I wanted to create a templated class which would wrap
a list, as followed :

#ifndef			__LISTCONTAINER_HH__
# define		__LISTCONTAINER_HH__

# include		<list>

template<typename T>
class			ListContainer
{
public:
  typedef std::list<T>				ListSubType;
  typedef typename ListSubType::size_type	IndexType;

private:
  ListSubType		*_elts;

public:
  ListContainer() : _elts(new ListSubType) {}
  virtual ~ListContainer() {
    delete _elts;
  }
};

#endif

And I implemented the odb::access::container_traits<ListContainer<T> *>
class (big file) :

#ifndef			__LISTCONTAINER_TRAITS_HXX__
# define		__LISTCONTAINER_TRAITS_HXX__

# include		<odb/pre.hxx>
# include		<odb/container-traits.hxx>
# include		"ListContainer.hpp"

namespace		odb
{
  template<typename T>
  class			access::container_traits<ListContainer<T> *>
  {
  public:
    static container_kind const				kind = ck_ordered;
    static bool const					smart = false;

    typedef ListContainer<T> *				container_type;

    typedef T						value_type;
    typedef typename ListContainer<T>::IndexType	index_type;

    typedef ordered_functions<index_type, value_type>	functions;

  public:
    static void		persist(container_type const &c, functions const &f) {
      index_type	i = 0;

      for (auto it = c->_elts->cbegin() ; it != c->_elts->cend() ; ++it) {
	f.insert(i++, *it);
      }
    }

    static void		load(container_type &c, bool more, functions const &f) {
      c->_elts->clear();

      while (more) {
	index_type	dummy = 0;

	c->_elts->push_back(value_type());
	more = f.insert(dummy, c->_elts->back());
      }
    }

    static void		update(container_type const &c, functions const &f) {
      index_type	i = 0;

      f.delete_();
      for (auto it = c->_elts->cbegin() ; it != c->_elts->cend() ; ++it) {
	f.insert(i++, *it);
      }
    }

    static void		erase(functions const &f) {
      f.delete_();
    }
  };
}

# include		<odb/post.hxx>

#endif

The ListContainer.options file :

--odb-epilogue '#include "ListContainer-traits.hxx"'
--hxx-prologue '#include "ListContainer-traits.hxx"'

In theory, theses classes would allow me to do this :

#ifndef                 __PERSON_HH__
# define                __PERSON_HH__

# include               "Persistent.hh"
# include               "Nameable.hh"
# include               "ListContainer.hpp"

class                   Person : public Persistent, public Nameable
{
  friend class          odb::access;

private:
  unsigned char                 _age;
  ListContainer<Person *>       *_friends;

private:
  Person();

public:
  Person(std::string const &name, unsigned char const age = 0);
  Person(Person const &rhs);

  virtual ~Person();

  Person                &operator=(Person const &rhs);

  unsigned char         getAge() const;
  void                  setAge(unsigned char const age);
};

# ifdef ODB_COMPILER
#  pragma db object(Person)
# endif

#endif

I don't know if I did something wrong but when I try to compile this with
the command :
odb  -d mysql --generate-schema-only --std c++11 --at-once --options-file
ListContainer.options --input-name schema.sql Persistent.hh Nameable.hh
Person.hh

ODB crashes (Segmentation Fault), that's what it prints :
*** WARNING *** there are active plugins, do not report this as a bug unless
you can reproduce it without enabling any plugins.
Event                            | Plugins
PLUGIN_START_UNIT                | odb
PLUGIN_PRAGMAS                   | odb
PLUGIN_OVERRIDE_GATE             | odb
In file included from /usr/include/c++/4.8.2/bits/stl_map.h:63:0,
                 from /usr/include/c++/4.8.2/map:61,
                 from /usr/include/odb/std-map-traits.hxx:10,
                 from /usr/include/odb/container-traits.hxx:207,
                 from ListContainer-traits.hxx:15,
                 from <odb-epilogue-1>:1:
/usr/include/c++/4.8.2/tuple: In member function ‘void
std::tuple<>::swap(std::tuple<>&)’:
/usr/include/c++/4.8.2/tuple:515:12: internal compiler error: Segmentation fault
       void swap(tuple&) noexcept { /* no-op */ }
            ^
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://bugs.archlinux.org/> for instructions.

Here's my problem. Note that odb doesn't crashes when I comment the line
'ListContainer<Person *> *_friends;' in the Person class.
I hope I made my problem clear, if not, feel free to ask more details.

So, is it possible to make a templated custom container with ODB ?
If it is, what did I miss ?

Thanks in advance.

Alexis MESTAG



More information about the odb-users mailing list