From 566742d0574866b7d3f6812400f7c9e63f5acd70 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Wed, 31 Jan 2024 14:39:24 -0600 Subject: [PATCH] Avoid creating objects that Godot is going to use placement new to initialize --- include/godot_cpp/core/memory.hpp | 28 ++++++++++++++++++ src/variant/variant.cpp | 48 +++++++++++++++---------------- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/include/godot_cpp/core/memory.hpp b/include/godot_cpp/core/memory.hpp index 97a2b13b..5036c4f7 100644 --- a/include/godot_cpp/core/memory.hpp +++ b/include/godot_cpp/core/memory.hpp @@ -190,6 +190,34 @@ struct _GlobalNilClass { static _GlobalNil _nil; }; +// This is for allocating uninitialized memory for passing to GDExtension functions that +// will use placement new to construct a new object. +// +// NOTE: You MUST make sure that the value is initialized before the object goes out of +// scope, otherwise the destructor will be run on junk memory and "bad things" will happen. +template +class ManuallyInitializedValue { + typename std::aligned_storage::type data; + +public: + ManuallyInitializedValue() {} + + ManuallyInitializedValue(const ManuallyInitializedValue &) = delete; + ManuallyInitializedValue &operator=(const ManuallyInitializedValue &) = delete; + + ~ManuallyInitializedValue() { + reinterpret_cast(&data)->~T(); + } + + T &get() { + return *reinterpret_cast(&data); + } + + T *ptr() { + return reinterpret_cast(&data); + } +}; + } // namespace godot #endif // GODOT_MEMORY_HPP diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 945d6f40..3eeeed0d 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -303,9 +303,9 @@ Variant::operator float() const { } Variant::operator String() const { - String result; - to_type_constructor[STRING](result._native_ptr(), _native_ptr()); - return result; + ManuallyInitializedValue result; + to_type_constructor[STRING](result.ptr(), _native_ptr()); + return result.get(); } Variant::operator Vector2() const { @@ -405,9 +405,9 @@ Variant::operator Color() const { } Variant::operator StringName() const { - StringName result; - to_type_constructor[STRING_NAME](result._native_ptr(), _native_ptr()); - return result; + ManuallyInitializedValue result; + to_type_constructor[STRING_NAME](result.ptr(), _native_ptr()); + return result.get(); } Variant::operator NodePath() const { @@ -459,15 +459,15 @@ Variant::operator Signal() const { } Variant::operator Dictionary() const { - Dictionary result; - to_type_constructor[DICTIONARY](result._native_ptr(), _native_ptr()); - return result; + ManuallyInitializedValue result; + to_type_constructor[DICTIONARY](result.ptr(), _native_ptr()); + return result.get(); } Variant::operator Array() const { - Array result; - to_type_constructor[ARRAY](result._native_ptr(), _native_ptr()); - return result; + ManuallyInitializedValue result; + to_type_constructor[ARRAY](result.ptr(), _native_ptr()); + return result.get(); } Variant::operator PackedByteArray() const { @@ -607,39 +607,39 @@ void Variant::set_keyed(const Variant &key, const Variant &value, bool &r_valid) } Variant Variant::get(const Variant &key, bool *r_valid) const { - Variant result; + ManuallyInitializedValue result; GDExtensionBool valid; - internal::gdextension_interface_variant_get(_native_ptr(), key._native_ptr(), result._native_ptr(), &valid); + internal::gdextension_interface_variant_get(_native_ptr(), key._native_ptr(), result.ptr(), &valid); if (r_valid) { *r_valid = PtrToArg::convert(&valid); } - return result; + return result.get(); } Variant Variant::get_named(const StringName &name, bool &r_valid) const { - Variant result; + ManuallyInitializedValue result; GDExtensionBool valid; - internal::gdextension_interface_variant_get_named(_native_ptr(), name._native_ptr(), result._native_ptr(), &valid); + internal::gdextension_interface_variant_get_named(_native_ptr(), name._native_ptr(), result.ptr(), &valid); r_valid = PtrToArg::convert(&valid); - return result; + return result.get(); } Variant Variant::get_indexed(int64_t index, bool &r_valid, bool &r_oob) const { - Variant result; + ManuallyInitializedValue result; GDExtensionBool valid; GDExtensionBool oob; - internal::gdextension_interface_variant_get_indexed(_native_ptr(), index, result._native_ptr(), &valid, &oob); + internal::gdextension_interface_variant_get_indexed(_native_ptr(), index, result.ptr(), &valid, &oob); r_valid = PtrToArg::convert(&valid); r_oob = PtrToArg::convert(&oob); - return result; + return result.get(); } Variant Variant::get_keyed(const Variant &key, bool &r_valid) const { - Variant result; + ManuallyInitializedValue result; GDExtensionBool valid; - internal::gdextension_interface_variant_get_keyed(_native_ptr(), key._native_ptr(), result._native_ptr(), &valid); + internal::gdextension_interface_variant_get_keyed(_native_ptr(), key._native_ptr(), result.ptr(), &valid); r_valid = PtrToArg::convert(&valid); - return result; + return result.get(); } bool Variant::in(const Variant &index, bool *r_valid) const {