From 32a06cad1df9f94aa14cf9c8ae7a86989a464b87 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Fri, 5 Apr 2019 17:22:55 +0300 Subject: [core] Move should not call destructors --- include/mbgl/style/conversion_impl.hpp | 25 ++----- test/style/conversion/conversion_impl.test.cpp | 100 +++++++++++++++++++++++++ test/test-files.json | 1 + 3 files changed, 108 insertions(+), 18 deletions(-) create mode 100644 test/style/conversion/conversion_impl.test.cpp diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index 27b2ee1917..0551187f6a 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -89,29 +89,20 @@ public: new (static_cast(&storage)) std::decay_t(std::forward(value)); } - Convertible(Convertible&& v) - : vtable(v.vtable) - { - if (vtable) { - vtable->move(std::move(v.storage), this->storage); - } + Convertible(Convertible&& v) : vtable(v.vtable) { + vtable->move(std::move(v.storage), storage); } ~Convertible() { - if (vtable) { - vtable->destroy(storage); - } + vtable->destroy(storage); } Convertible& operator=(Convertible&& v) { - if (vtable) { + if (this != &v) { vtable->destroy(storage); + vtable = v.vtable; + vtable->move(std::move(v.storage), storage); } - vtable = v.vtable; - if (vtable) { - vtable->move(std::move(v.storage), this->storage); - } - v.vtable = nullptr; return *this; } @@ -235,9 +226,7 @@ private: using Traits = ConversionTraits; static VTable vtable = { [] (Storage&& src, Storage& dest) { - auto srcValue = reinterpret_cast(src); - new (static_cast(&dest)) T(std::move(srcValue)); - srcValue.~T(); + new (static_cast(&dest)) T(reinterpret_cast(src)); }, [] (Storage& s) { reinterpret_cast(s).~T(); diff --git a/test/style/conversion/conversion_impl.test.cpp b/test/style/conversion/conversion_impl.test.cpp new file mode 100644 index 0000000000..633d77886f --- /dev/null +++ b/test/style/conversion/conversion_impl.test.cpp @@ -0,0 +1,100 @@ +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +class MockConvertible { +public: + MockConvertible() = default; + MockConvertible(int* counter_) : counter(counter_) {} + + MockConvertible(MockConvertible&& other) noexcept : counter(other.counter) {} + + ~MockConvertible() { + ++*counter; + } + + int* counter = nullptr; +}; + +template <> +class ConversionTraits { +public: + static bool isUndefined(const MockConvertible&) { + return false; + } + + static bool isArray(const MockConvertible&) { + return false; + } + + static bool isObject(const MockConvertible&) { + return false; + } + + static std::size_t arrayLength(const MockConvertible&) { + return 0u; + } + + static MockConvertible arrayMember(const MockConvertible&, std::size_t) { + return {}; + } + + static optional objectMember(const MockConvertible&, const char *) { + return nullopt; + } + + template + static optional eachMember(const MockConvertible&, Fn&&) { + return nullopt; + } + + static optional toBool(const MockConvertible&) { + return nullopt; + } + + static optional toNumber(const MockConvertible&) { + return nullopt; + } + + static optional toDouble(const MockConvertible&) { + return nullopt; + } + + static optional toString(const MockConvertible&) { + return nullopt; + } + + static optional toValue(const MockConvertible&) { + return nullopt; + } + + static optional toGeoJSON(const MockConvertible&, Error&) { + return nullopt; + } +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl + +using namespace mbgl; +using namespace mbgl::style; +using namespace mbgl::style::conversion; + +TEST(Conversion, Move) { + int dtorCounter = 0; + + { + MockConvertible mock(&dtorCounter); + Convertible a(std::move(mock)); + Convertible b(std::move(a)); + a = std::move(b); + Convertible* c = &a; + a = std::move(*c); + } + + ASSERT_EQ(dtorCounter, 4); +} diff --git a/test/test-files.json b/test/test-files.json index 498237e072..f958fba0d3 100644 --- a/test/test-files.json +++ b/test/test-files.json @@ -49,6 +49,7 @@ "test/storage/online_file_source.test.cpp", "test/storage/resource.test.cpp", "test/storage/sqlite.test.cpp", + "test/style/conversion/conversion_impl.test.cpp", "test/style/conversion/function.test.cpp", "test/style/conversion/geojson_options.test.cpp", "test/style/conversion/layer.test.cpp", -- cgit v1.2.1