在C ++中向std :: vector添加任意数量元素的最有效方法是什么?

时间:2016-10-27 00:36:56

标签: c++ c++11 vector variadic-functions

我有一个已定义的类A和一个std::vector vec,它存储了一系列A个实例。我尝试编写一个函数,将A个实例附加到vec

我应该vec.reserve()vec.push_back()一起使用,因为不断调整矢量大小很昂贵吗?或者,我应该使用vec.insert()吗?

目前,我不确定是否应该设计函数接受使用可变参数函数的可变数量的参数或我想要组合的A个实例的向量,然后与{{1连接}}?

设计此功能的有效方法是什么(速度至关重要,A是一个复杂的类)?

2 个答案:

答案 0 :(得分:1)

我认为以下内容应涵盖常见案例。 rref_capture技巧来自this answer。重点是尽可能移动值。

您还可以使用可变参数模板版本,如另一个答案中所示。

// https://github.com/KubaO/stackoverflown/tree/master/questions/vector-append-40274282
#include <array>
#include <cassert>
#include <initializer_list>
#include <iterator>
#include <type_traits>
#include <vector>

template<typename T>
class rref_capture {
   T* ptr;
public:
   rref_capture(T&& x) : ptr(&x) {}
   operator T&& () const { return std::move(*ptr); } // restitute rvalue ref
};

template <typename T>
void append(std::vector<T> & v,
            typename std::decay<std::initializer_list<rref_capture<T>>>::type u) {
   v.reserve(v.size() + u.size());
   for (auto && item : u)
      v.push_back(std::move(item));
}

template <typename T, typename U>
void append(std::vector<T> & v, U && u) {
   v.reserve(v.size() + std::distance(std::begin(u), std::end(u)));
   for (auto & item : u)
      v.push_back(std::move(item));
}

template <typename T, typename U>
void append(std::vector<T> & v, U & u) {
   v.reserve(v.size() + std::distance(std::begin(u), std::end(u)));
   for (auto & item : u)
      v.push_back(item);
}

struct A {
   static int copies, moves;
   A() {}
   A(A&&) { moves++; }
   A(const A&) { copies++; }
   A& operator=(const A&) { copies++; return *this; }
   static void reset() { A::copies = 0; A::moves = 0; }
};
int A::copies, A::moves;

int main() {
   std::vector<A> vec;
   vec.reserve(100);

   A::reset();
   append(vec, {A(), A()});
   assert(A::copies == 0 && A::moves == 2 && vec.size() == 2);

   auto vec2 = vec;
   A::reset();
   append(vec, vec2);
   assert(A::copies == 2 && A::moves == 0 && vec.size() == 4);

   A::reset();
   append(vec, std::move(vec2));
   assert(A::copies == 0 && A::moves == 2 && vec.size() == 6);

   A::reset();
   append(vec, std::array<A,2>{A(), A()});
   assert(A::copies == 0 && A::moves == 2 && vec.size() == 8);

   const std::vector<A> cvec{2};
   A::reset();
   append(vec, cvec);
   assert(A::copies == 2 && A::moves == 0 && vec.size() == 10);

   A arr[2];
   A::reset();
   append(vec, arr);
   assert(A::copies == 2 && A::moves == 0 && vec.size() == 12);
}

答案 1 :(得分:0)

嗯......我想你可以使用reserve()一次,然后使用push_back()添加单个元素。

以下示例使用int代替class A,但应该提供想法

#include <vector>
#include <iostream>

template <typename T>
void appendT (std::vector<T> & v)
 { }

template <typename T, typename ... Ts>
void appendT (std::vector<T> & v, T t, Ts ... ts)
 { 
   v.push_back(t);

   appendT(v, ts...);
 }

template <typename T, typename ... Ts>
void appendTs (std::vector<T> & v, Ts ... ts)
 {
   v.reserve(v.size() + sizeof...(Ts));

   appendT(v, ts...);
 }

int main()
 {
   std::vector<int> v { 2, 3, 5 };

   appendTs(v, 7, 11, 13, 17);

   for ( auto const & i : v )
      std::cout << ' ' << i; // print " 2 3 5 7 11 13 17"

   std::cout << std::endl;
 }

如果你不喜欢递归解决方案,你可以写一个appendTs()来完成所有的工作(但我不知道如何避免这个问题&#34;警告:未使用的变量&#39;未使用&#39;&#34; 我知道如何避免警告,但我不知道这是不是一个好主意 Kuba Ober建议我采用一种优雅的方法来避免警告。

#include <vector>
#include <iostream>

template <typename T, typename ... Ts>
void appendTs (std::vector<T> & v, Ts ... ts)
 {
   v.reserve(v.size() + sizeof...(Ts));

   // the first '0' is to avoid an error when sizeof...(Ts) is zero
   char unused[] { '0', (v.push_back(ts), '0')... };

   // the following statement is to avoid an annoing "unused variable
   // 'unused'" warning (thanks Kuba Ober)
   (void)unused;
 }

int main()
 {
   std::vector<int> v { 2, 3, 5 };

   appendTs(v, 7, 11, 13, 17);

   for ( auto const & i : v )
      std::cout << ' ' << i; // print " 2 3 5 7 11 13 17"

   std::cout << std::endl;
 }