diff --git a/include/evmc/evmc.hpp b/include/evmc/evmc.hpp index 7d2344c..58bf3cd 100644 --- a/include/evmc/evmc.hpp +++ b/include/evmc/evmc.hpp @@ -80,11 +80,32 @@ public: class vm { public: + vm() noexcept = default; + /// Converting constructor from evmc_instance. explicit vm(evmc_instance* instance) noexcept : m_instance{instance} {} /// Destructor responsible for automatically destroying the VM instance. - ~vm() noexcept { m_instance->destroy(m_instance); } + ~vm() noexcept + { + if (m_instance) + m_instance->destroy(m_instance); + } + + vm(const vm&) = delete; + vm& operator=(const vm&) = delete; + + /// Move constructor. + vm(vm&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; } + + /// Move assignment operator. + vm& operator=(vm&& other) noexcept + { + this->~vm(); + m_instance = other.m_instance; + other.m_instance = nullptr; + return *this; + } /// The constructor that captures a VM instance and configures the instance /// with provided list of options. @@ -128,7 +149,7 @@ public: } private: - evmc_instance* const m_instance = nullptr; + evmc_instance* m_instance = nullptr; }; /// The EVMC Host interface diff --git a/test/unittests/test_cpp.cpp b/test/unittests/test_cpp.cpp index 8069120..68c0887 100644 --- a/test/unittests/test_cpp.cpp +++ b/test/unittests/test_cpp.cpp @@ -70,6 +70,42 @@ TEST(cpp, vm_set_option) EXPECT_EQ(vm.set_option("1", "2"), EVMC_SET_OPTION_INVALID_NAME); } +TEST(cpp, vm_move) +{ + static int destroy_counter = 0; + const auto template_instance = + evmc_instance{EVMC_ABI_VERSION, "", "", [](evmc_instance*) { ++destroy_counter; }, + nullptr, nullptr, nullptr, nullptr}; + + EXPECT_EQ(destroy_counter, 0); + { + auto v1 = template_instance; + auto v2 = template_instance; + + auto vm1 = evmc::vm{&v1}; + vm1 = evmc::vm{&v2}; + (void)vm1; + } + EXPECT_EQ(destroy_counter, 2); + { + auto v1 = template_instance; + + auto vm1 = evmc::vm{&v1}; + vm1 = evmc::vm{}; + (void)vm1; + } + EXPECT_EQ(destroy_counter, 3); + { + auto v1 = template_instance; + + auto vm1 = evmc::vm{&v1}; + auto vm2 = std::move(vm1); + auto vm3 = std::move(vm2); + (void)vm3; + } + EXPECT_EQ(destroy_counter, 4); +} + TEST(cpp, host) { // Use example host to execute all methods from the C++ host wrapper.