Luabind: не могу вернуть shared_ptr

Я пытаюсь вернуть std::shared_ptr из метода, связанного с Luabind, но, похоже, он не распознает тип.

Код Luabind:

module(lua)
[
    class_<Character, BaseEntity, std::shared_ptr<Character> > ("Character"),
        def("createCharacter", &Character::createCharacter)
];

код createCharacter:

std::shared_ptr<Character> Character::createCharacter(Game* gameInstance, const Character::CharacterSetup& characterSetup, string sprite, b2World* world)
{
    return std::shared_ptr<Character>(new Character(gameInstance, characterSetup, sprite, world));
}

Если я вызову этот метод в скрипте Lua, ничего не будет возвращено, и выполнение на этом остановится. Однако, если я изменю метод, чтобы вернуть Character*, он будет работать, как и ожидалось. Некоторые гуглы говорят мне, что возврат shared_ptr не должен быть проблемой.

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

Кроме того, у меня есть этот код, поэтому Luabind может понять std::shared_ptr:

namespace luabind
{
    template <typename T>
    T* get_pointer(std::shared_ptr<T> const& p)
    {
        return p.get();
    }
}

person tacospice    schedule 23.02.2013    source источник
comment
Вы пробовали boost::shared_ptr<T> вместо этого?   -  person Luc Danton    schedule 23.02.2013
comment
Я не слишком знаком с luabind, но если он не хранит общий указатель, а просто использует get_pointer() для получения реального указателя, он удалит последнюю ссылку (таким образом, удалив объект), в то время как он сохранит (теперь оборванный ) указатель. Во-первых, убедитесь, что ваш класс правильно сделан некопируемым. Во-вторых, добавьте точки останова в конструктор и деструктор.   -  person Ulrich Eckhardt    schedule 23.02.2013


Ответы (1)


Пришлось решать ту же проблему.

Это немного сложно. В основном вам нужно определить функцию с прототипом

template <typename T>
T* get_pointer(std::shared_ptr<T> const&);

Кроме того, эта функция должна находиться в том же пространстве имен, что и std::shared_ptr, то есть std::. Обратите внимание, что функция в глобальном пространстве имен или luabind пространстве имен, как у вас, не будет работать, поскольку luabind использует специальные приемы, чтобы убедиться, что при проверке того, является ли определенный тип умным указателем, используется только ADL. Единственный способ обойти это — определить вашу функцию в пространстве имен luabind::detail::has_get_pointer_, а не только в luabind.

Но определение вашей функции только в этом пространстве имен тоже не сработает (по крайней мере, для Boost ‹ 1.53). Хотя определение функции в пространстве имен std технически не разрешено стандартом C++, это единственный возможный способ для Boost ‹ 1.53. Однако, начиная с версии 1.53, Boost определяет собственные перегрузки boost::get_pointer() для std::shared_ptrstd::unique_ptr). Для этой версии достаточно сделать get_pointer() Boost видимым в пространстве имен luabind::detail::has_get_pointer_, поскольку luabind является using этой функцией везде, где используются интеллектуальные указатели (см. luabind/get_pointer.hpp). Тогда определение функции в std даже не сработает, потому что luabind спровоцирует неоднозначный вызов.

Итак, если вам нужна перегрузка get_pointer() для std::shared_ptr, которая работает для Boost ‹ 1,53 и >= 1,53, а также для MSVC 10 (и, возможно, 9) (они определяют shared_ptr в std::tr1 вместо std), я могу предложить вам мой (исторически выросший; - )) заголовок:

#ifndef SHAREDPTR_CONVERTER_HPP_INCLUDED
#define SHAREDPTR_CONVERTER_HPP_INCLUDED SHAREDPTR_CONVERTER_HPP_INCLUDED

#include <boost/version.hpp>

#if BOOST_VERSION >= 105300

#include <boost/get_pointer.hpp>


namespace luabind { namespace detail { namespace has_get_pointer_ {
    template<class T>
    T * get_pointer(std::shared_ptr<T> const& p) { return p.get(); }
}}}

#else // if BOOST_VERSION < 105300

#include <memory>

// Not standard conforming: add function to ::std(::tr1)
namespace std {

#if defined(_MSC_VER) && _MSC_VER < 1700
namespace tr1 {
#endif

    template<class T>
    T * get_pointer(shared_ptr<T> const& p) { return p.get(); }

#if defined(_MSC_VER) && _MSC_VER < 1700
} // namespace tr1
#endif

} // namespace std

#endif // if BOOST_VERSION < 105300

#endif
person Oberon    schedule 04.03.2013
comment
обалденно обалденно обалденно. Спасибо Спасибо спасибо. - person morgancodes; 25.06.2014