diff --git a/cheatsheet.md b/cheatsheet.md index ce8e04a0..c37045f7 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -163,6 +163,28 @@ chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as(); // works with an static_cast(chai.eval("5.3+2.1")); // this version only works if we know that it's a double ``` +### Conversion Caveats + +Conversion to `std::shared_ptr &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior + +```cpp +// ok this is supported, you can register it with chaiscript engine +void nullify_shared_ptr(std::shared_ptr &t) { + t == nullptr +} +``` + +```cpp +int main() +{ + // do some stuff and create a chaiscript instance + std::shared_ptr &ptr = chai.eval &>(somevalue); + // DO NOT do this. Taking a non-const reference to a shared_ptr is not + // supported and causes undefined behavior in the chaiscript engine +} +``` + + ## Sharing Values ``` diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 505b1e1f..b4e1826b 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -173,6 +173,18 @@ namespace chaiscript { }; + template + struct Cast_Helper_Inner &> + { + typedef Boxed_Value::Sentinel Result_Type; + + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) + { + std::shared_ptr &res = ob.get().cast >(); + return ob.pointer_sentinel(res); + } + }; + /// Cast_Helper_Inner for casting to a const std::shared_ptr & type template struct Cast_Helper_Inner > : Cast_Helper_Inner > diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 5a49119f..ff09cc19 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -231,6 +231,50 @@ namespace chaiscript return m_data->m_type_info.bare_equal(ti); } + template + struct Sentinel { + Sentinel(std::shared_ptr &ptr, Data &data) + : m_ptr(ptr), m_data(data) + { + } + + ~Sentinel() + { + // save new pointer data + m_data.get().m_data_ptr = m_ptr.get().get(); + m_data.get().m_const_data_ptr = m_ptr.get().get(); + } + + Sentinel& operator=(Sentinel&&s) { + m_ptr = std::move(s.m_ptr); + m_data = std::move(s.m_data); + } + + Sentinel(Sentinel &&s) + : m_ptr(std::move(s.m_ptr)), + m_data(std::move(s.m_data)) + { + } + + operator std::shared_ptr&() const + { + return m_ptr.get(); + } + + Sentinel &operator=(const Sentinel &) = delete; + Sentinel(Sentinel&) = delete; + + std::reference_wrapper> m_ptr; + std::reference_wrapper m_data; + }; + + + template + Sentinel pointer_sentinel(std::shared_ptr &ptr) const + { + return Sentinel(ptr, *(m_data.get())); + } + bool is_null() const CHAISCRIPT_NOEXCEPT { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);