Przeglądaj źródła

any: safe self-assignment

skypjack 5 miesięcy temu
rodzic
commit
740cf006d9
2 zmienionych plików z 22 dodań i 24 usunięć
  1. 12 14
      src/entt/core/any.hpp
  2. 10 10
      test/entt/core/any.cpp

+ 12 - 14
src/entt/core/any.hpp

@@ -238,7 +238,7 @@ public:
     /*! @brief Frees the internal storage, whatever it means. */
     ~basic_any() {
         destroy_if_owner();
-        }
+    }
 
     /**
      * @brief Copy assignment operator.
@@ -259,25 +259,23 @@ public:
 
     /**
      * @brief Move assignment operator.
-     *
-     * @warning
-     * Self-moving puts objects in a safe but unspecified state.
-     *
      * @param other The instance to move from.
      * @return This any object.
      */
     basic_any &operator=(basic_any &&other) noexcept {
-        reset();
+        if(this != &other) {
+            destroy_if_owner();
 
-        if(other.mode == any_policy::embedded) {
-            other.vtable(request::move, other, this);
-        } else if(other.mode != any_policy::empty) {
-            instance = std::exchange(other.instance, nullptr);
-        }
+            if(other.mode == any_policy::embedded) {
+                other.vtable(request::move, other, this);
+            } else if(other.mode != any_policy::empty) {
+                instance = std::exchange(other.instance, nullptr);
+            }
 
-        vtable = other.vtable;
-        descriptor = other.descriptor;
-        mode = other.mode;
+            vtable = other.vtable;
+            descriptor = other.descriptor;
+            mode = other.mode;
+        }
 
         return *this;
     }

+ 10 - 10
test/entt/core/any.cpp

@@ -307,11 +307,11 @@ TEST(Any, SBOSelfMoveAssignment) {
     // avoid warnings due to self-assignment
     any = std::move(*&any);
 
-    ASSERT_FALSE(any);
-    ASSERT_FALSE(any.owner());
-    ASSERT_EQ(any.policy(), entt::any_policy::empty);
-    ASSERT_EQ(any.info(), entt::type_id<void>());
-    ASSERT_EQ(any.data(), nullptr);
+    ASSERT_TRUE(any);
+    ASSERT_TRUE(any.owner());
+    ASSERT_EQ(any.policy(), entt::any_policy::embedded);
+    ASSERT_EQ(any.info(), entt::type_id<int>());
+    ASSERT_EQ(entt::any_cast<int>(any), 2);
 }
 
 TEST(Any, SBODirectAssignment) {
@@ -633,11 +633,11 @@ TEST(Any, NoSBOSelfMoveAssignment) {
     // avoid warnings due to self-assignment
     any = std::move(*&any);
 
-    ASSERT_FALSE(any);
-    ASSERT_FALSE(any.owner());
-    ASSERT_EQ(any.policy(), entt::any_policy::empty);
-    ASSERT_EQ(any.info(), entt::type_id<void>());
-    ASSERT_EQ(any.data(), nullptr);
+    ASSERT_TRUE(any);
+    ASSERT_TRUE(any.owner());
+    ASSERT_EQ(any.policy(), entt::any_policy::dynamic);
+    ASSERT_EQ(any.info(), entt::type_id<fat>());
+    ASSERT_EQ(entt::any_cast<fat>(any), instance);
 }
 
 TEST(Any, NoSBODirectAssignment) {