[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