Сопоставитель базы данных C++ ODB: невозможно использовать std::weak_ptr в отношении

Я пытаюсь смоделировать отношения «один ко многим» с ODB. В основном я пытаюсь воссоздать пример в https://www.codegenesis.com/products/odb/doc/manual.xhtml#6.2.2

Я должен использовать std::weak_ptr для одной стороны отношений, чтобы избежать проблем с круговым владением. Однако мой очень простой пример кода не компилируется, так как ODB не очень хорошо работает с std::weak_ptr.

В моем примере у каждого Bar есть ровно один Foo, а у каждого Foo есть несколько Bar. Это мой код:

#include <odb/core.hxx>
#include <string>
#include <memory>
#include <vector>

// Forward
class Foo;

#pragma db object
class Bar {
public:
    // A Bar has exactly *one* Foo
    #pragma db not_null
    std::shared_ptr<Foo> cfg;

private:
    #pragma db id auto
    unsigned long id_;
    friend class odb::access;
};

#pragma db object
class Foo {
public:
    // A Foo has multiple Bars
    // Using std::weak_ptr here instead of std::shared_ptr to avoid circular
    // ownership
    #pragma db value_not_null inverse(cfg)
    std::vector<std::weak_ptr<Bar>> entries;

private:
    #pragma db id auto
    unsigned long id_;
    friend class odb::access;
};

int main() {}

Я генерирую код базы данных с помощью:

odb --std c++11 --database sqlite --generate-query --generate-schema --at-once main.hpp

И я компилирую так:

g++ --std=c++11 main.hpp main-odb.cxx

(Я знаю, что это приведет к сбою при компоновке - я просто пытаюсь его скомпилировать.)

Мой компилятор (GCC 7) говорит мне:

main-odb.cxx: In static member function ‘static void odb::access::object_traits_impl<Foo, (odb::database_id)1u>::entries_traits::init(odb::access::object_traits_impl<Foo, (odb::database_id)1u>::entries_traits::value_type&, const odb::access::object_traits_impl<Foo, (odb::database_id)1u>::entries_traits::data_image_type&, odb::database*)’:
main-odb.cxx:794:43: error: no matching function for call to ‘std::weak_ptr<Bar>::weak_ptr(odb::object_traits<Bar>::pointer_type)’
             obj_traits::object_type > (id));
                                           ^
In file included from /usr/include/c++/5/memory:82:0,
                 from main.hpp:3,
                 from main-odb.hxx:16,
                 from main-odb.cxx:7:
/usr/include/c++/5/bits/shared_ptr.h:492:2: note: candidate: template<class _Tp1, class> std::weak_ptr<_Tp>::weak_ptr(std::weak_ptr<_Tp1>&&)
  weak_ptr(weak_ptr<_Tp1>&& __r) noexcept
  ^
/usr/include/c++/5/bits/shared_ptr.h:492:2: note:   template argument deduction/substitution failed:
main-odb.cxx:794:43: note:   mismatched types ‘std::weak_ptr<_Tp>’ and ‘odb::object_traits<Bar>::pointer_type {aka Bar*}’
             obj_traits::object_type > (id));

Есть еще три кандидата, которых я пропустил. Важная часть: ODB пытается где-то создать std::weak_ptr<Bar> из Bar *, что, очевидно, невозможно. Это должно было бы создать его из файла std::shared_ptr<Bar>. Однако в документации ODB прямо говорится, что в этих случаях следует (и фактически необходимо) использовать std::weak_ptr.

Что я делаю не так?


person Lukas Barth    schedule 02.08.2018    source источник
comment
Bar содержит указатель на Foo, попробуйте использовать std::enable_shared_from_this в Foo.   -  person seccpur    schedule 02.08.2018
comment
Хорошая идея, однако это код в ODB, который пытается создать std::weak_ptr<Bar> из Bar *. Я не понимаю, как заставить это использовать Bar::shared_from_this()? Реализация пользовательского преобразования из Bar в std::shared_ptr<Bar> (которое было бы допустимым аргументом для конструктора std::weak_ptr<Bar>) также не работает, поскольку используется Bar *, а не Bar.   -  person Lukas Barth    schedule 02.08.2018


Ответы (1)


Хорошо, я нашел решение (не уверен, что это лучшее решение):

Вы можете заставить ODB везде использовать std::shared_ptr<Bar> вместо Bar *. Вы делаете это, определяя свой класс как:

#pragma db object pointer(std::shared_ptr)
class Bar {
...

Таким образом, когда создается std::weak_ptr<Bar>, он создается из std::shared_ptr<Bar>, что работает. Вы также можете указать тип указателя, который будет использоваться в пространстве имен или глобальной области видимости, см. ">https://www.codegenesis.com/products/odb/doc/manual.xhtml#3.3

person Lukas Barth    schedule 02.08.2018