small_vector should not require a copy-ctr from its element type unless it needs it.
authorDmitry Pleshkov <bort@fb.com>
Tue, 14 Mar 2017 06:33:57 +0000 (23:33 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 14 Mar 2017 06:39:18 +0000 (23:39 -0700)
Summary:
Use default constructor directly, instead of copying the element introduced by default parameter value.
This behavior is compatible with `std::vector`.

Reviewed By: ot, bixue2010, luciang

Differential Revision: D4700611

fbshipit-source-id: d3bd82c46c2857f5abcbec5dd2a64aaa85eaefe4

folly/small_vector.h
folly/test/small_vector_test.cpp

index db36acc072b5c9ddd0de5cf83a235a683435447c..4ef59b67e96565ab86837917c2c3d863ffee7dbf 100644 (file)
@@ -47,6 +47,7 @@
 #include <folly/Malloc.h>
 #include <folly/Portability.h>
 #include <folly/SmallLocks.h>
+#include <folly/Traits.h>
 #include <folly/portability/BitsFunctexcept.h>
 #include <folly/portability/Constexpr.h>
 #include <folly/portability/Malloc.h>
@@ -393,8 +394,12 @@ class small_vector
     constructImpl(il.begin(), il.end(), std::false_type());
   }
 
-  explicit small_vector(size_type n, value_type const& t = value_type()) {
-    doConstruct(n, t);
+  explicit small_vector(size_type n) {
+    doConstruct(n, [&](void* p) { new (p) value_type(); });
+  }
+
+  small_vector(size_type n, value_type const& t) {
+    doConstruct(n, [&](void* p) { new (p) value_type(t); });
   }
 
   template<class Arg>
@@ -882,13 +887,12 @@ private:
     }
   }
 
-  void doConstruct(size_type n, value_type const& val) {
+  template <typename InitFunc>
+  void doConstruct(size_type n, InitFunc&& func) {
     makeSize(n);
     this->setSize(n);
     try {
-      detail::populateMemForward(data(), n,
-        [&] (void* p) { new (p) value_type(val); }
-      );
+      detail::populateMemForward(data(), n, std::forward<InitFunc>(func));
     } catch (...) {
       if (this->isExtern()) {
         u.freeHeap();
@@ -900,7 +904,7 @@ private:
   // The true_type means we should forward to the size_t,value_type
   // overload.
   void constructImpl(size_type n, value_type const& val, std::true_type) {
-    doConstruct(n, val);
+    doConstruct(n, [&](void* p) { new (p) value_type(val); });
   }
 
   void makeSize(size_type size, value_type* v = nullptr) {
index 0190cbb84e4a72111e154834b8a455f1075fe1d4..db63d4918e660dc7734c6f1c5d8fa1747788954a 100644 (file)
@@ -832,3 +832,27 @@ TEST(small_vector, InputIterator) {
     ASSERT_EQ(smallV[i], expected[i]);
   }
 }
+
+TEST(small_vector, NoCopyCtor) {
+  struct Test {
+    Test() = default;
+    Test(const Test&) = delete;
+    Test(Test&&) = default;
+
+    int field = 42;
+  };
+
+  small_vector<Test> test(10);
+  ASSERT_EQ(test.size(), 10);
+  for (const auto& element : test) {
+    EXPECT_EQ(element.field, 42);
+  }
+}
+
+TEST(small_vector, ZeroInitializable) {
+  small_vector<int> test(10);
+  ASSERT_EQ(test.size(), 10);
+  for (const auto& element : test) {
+    EXPECT_EQ(element, 0);
+  }
+}