【发布时间】:2010-09-20 12:47:03
【问题描述】:
我有一个值数组,这些值从程序的不同部分传递给我的函数,我需要存储这些值以供以后处理。由于我不知道在处理数据之前我的函数会被调用多少次,所以我需要一个动态存储结构,所以我选择了std::vector。我不想对push_back 的所有值单独执行标准循环,如果我可以使用类似于memcpy 的内容将其全部复制,那就太好了。
【问题讨论】:
我有一个值数组,这些值从程序的不同部分传递给我的函数,我需要存储这些值以供以后处理。由于我不知道在处理数据之前我的函数会被调用多少次,所以我需要一个动态存储结构,所以我选择了std::vector。我不想对push_back 的所有值单独执行标准循环,如果我可以使用类似于memcpy 的内容将其全部复制,那就太好了。
【问题讨论】:
这里有很多答案,几乎所有人都能完成工作。
但是有一些误导性的建议!
以下是选项:
vector<int> dataVec;
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);
// Method 1: Copy the array to the vector using back_inserter.
{
copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}
// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
dataVec.reserve(dataVec.size() + dataArraySize);
copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}
// Method 3: Memcpy
{
dataVec.resize(dataVec.size() + dataArraySize);
memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}
// Method 4: vector::insert
{
dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}
// Method 5: vector + vector
{
vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}
长话短说,方法 4 使用 vector::insert 是 bsruth 场景的最佳选择。
这里有一些血腥的细节:
方法 1 可能是最容易理解的。只需从数组中复制每个元素并将其推入向量的后面。唉,它很慢。因为有一个循环(隐含在复制功能中),所以每个元素都必须单独处理;由于我们知道数组和向量是连续的块,因此无法提高性能。
方法 2 是对方法 1 的建议性能改进;只需在添加之前预先保留数组的大小。对于大型数组,这可能会有所帮助。然而,这里最好的建议是永远不要使用保留,除非分析表明您可以得到改进(或者您需要确保您的迭代器不会失效)。 Bjarne agrees。顺便说一句,我发现这种方法在大多数情况下执行最慢,尽管我正在努力全面解释为什么它经常明显比方法 1 慢... p>
方法 3 是老派的解决方案 - 在问题上扔一些 C!对 POD 类型运行良好且快速。在这种情况下,需要调用 resize,因为 memcpy 在向量范围之外工作,并且无法告诉向量其大小已更改。除了是一个丑陋的解决方案(字节复制!)之外,请记住,这只能用于 POD 类型。我永远不会使用这个解决方案。
方法 4 是最好的方法。它的含义很明确,它(通常)是最快的,并且适用于任何对象。将此方法用于此应用程序没有任何缺点。
方法 5 是对方法 4 的调整 - 将数组复制到向量中,然后附加它。不错的选择 - 通常快速且清晰。
最后,您知道可以使用向量代替数组,对吧?即使函数需要 c 样式的数组,您也可以使用向量:
vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");
希望能帮助到那里的人!
【讨论】:
&expr 不计算expr,它只计算它的地址。最后一个元素之后的指针 one 也是完全有效的。
dataVec.insert(dataVec.end(), dataArray, dataArray + dataArraySize); - 对我来说似乎更清楚。也无法从方法 5 中获得任何东西,只是看起来效率很低——除非编译器能够再次优化向量。
如果你在得到数组和数组大小后可以构造向量,你可以说:
std::vector<ValueType> vec(a, a + n);
...假设a 是您的数组,n 是它包含的元素数。否则,std::copy() w/resize() 会成功。
我会远离 memcpy(),除非您可以确定这些值是普通旧数据 (POD) 类型。
另外,值得注意的是,这些都没有真正避免 for 循环——这只是你是否必须在代码中看到它的问题。 O(n) 运行时性能对于复制值是不可避免的。
最后,请注意,对于大多数 STL 算法来说,C 风格的数组是完全有效的容器——原始指针等同于 begin(),而 (ptr + n) 等同于 end()。
【讨论】:
vec.assign(a, a+n),它比复制和调整大小更紧凑。
如果您所做的只是替换现有数据,那么您可以这样做
std::vector<int> data; // evil global :)
void CopyData(int *newData, size_t count)
{
data.assign(newData, newData + count);
}
【讨论】:
std::copy 就是你要找的东西。
【讨论】:
由于我只能编辑自己的答案,因此我将根据我的问题的其他答案做出综合答案。感谢所有回答的人。
使用std::copy,这仍然在后台迭代,但您不必输入代码。
int foo(int* data, int size)
{
static std::vector<int> my_data; //normally a class variable
std::copy(data, data + size, std::back_inserter(my_data));
return 0;
}
使用普通的memcpy。这可能最适合用于基本数据类型(即 int),但不适用于更复杂的结构或类数组。
vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
【讨论】:
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);
std::vector<int> myvector (dataArraySize );//target
std::copy ( myints, myints+dataArraySize , myvector.begin() );
//myvector now has 1,2,3,...10 :-)
【讨论】:
myints 是什么?
避免使用 memcpy,我说。除非你真的必须这样做,否则没有理由搞乱指针操作。此外,它仅适用于 POD 类型(如 int),但如果您正在处理需要构造的类型,它将失败。
【讨论】:
还有一个答案,因为那个人说“我不知道我的函数会被调用多少次”,你可以像这样使用向量插入方法将值数组附加到向量的末尾:
vector<int> x;
void AddValues(int* values, size_t size)
{
x.insert(x.end(), values, values+size);
}
我喜欢这种方式,因为向量的实现应该能够根据迭代器类型和类型本身优化插入值的最佳方式。你有点回复stl的实现了。
如果您需要保证最快的速度并且您知道您的类型是 POD 类型,那么我会推荐 Thomas 回答中的 resize 方法:
vector<int> x;
void AddValues(int* values, size_t size)
{
size_t old_size(x.size());
x.resize(old_size + size, 0);
memcpy(&x[old_size], values, size * sizeof(int));
}
【讨论】:
除了上面介绍的方法之外,您还需要确保使用 std::Vector.reserve()、std::Vector.resize() 或按大小构造向量,以确保您的向量具有其中有足够的元素来保存您的数据。否则,您将破坏内存。对于 std::copy() 或 memcpy() 都是如此。
这就是使用vector.push_back()的原因,你不能写超过vector的末尾。
【讨论】:
假设您知道向量中的项目有多大:
std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));
【讨论】: