如何从C样式数组初始化std :: vector?


174

std::vector从C型数组初始化a的最便宜方法是什么?

示例:在下面的类中,我有一个vector,但是由于外部限制,数据将作为C样式数组传递:

class Foo {
  std::vector<double> w_;
public:
  void set_data(double* w, int len){
   // how to cheaply initialize the std::vector?
}

显然,我可以调用w_.resize()然后循环遍历元素,或调用std::copy()。有没有更好的方法?


11
问题的症结在于,向量无法知道是否使用了相同的分配器来创建C样式数组。因此,向量必须使用其自己的分配器分配内存。否则,它可以简单地换出基础数组并将其替换为您的数组。
Void

Answers:


233

不要忘记,您可以将指针视为迭代器:

w_.assign(w, w + len);

3
这是实施质量的问题。由于迭代器具有指定其类别的标签,因此assign使用进行优化当然是免费的。至少在VC ++中,它确实做到了这一点。
帕维尔·米纳夫

38
快速解决方案可以是std :: vector <double> w_(w,w + len);
果酱

1
这会将元素复制到新创建的“ w_”存储中;“ w_.data”不会指向“ w”。您仍然必须取消分配“ w”。没有所有权转让
Indy9000

1
如果它是一个结尾元素,它应该没问题(就像v.end()是一个迭代器指向一个过去在类似情况下与矢量结束)。如果确实得到了断言,那么其他地方就会出现问题。
帕维尔·米纳夫

1
很快,当向量超出范围时,这会释放数组内存吗?
阿德里安·科赫

41

您使用了初始化一词,因此不清楚这是一次分配还是可以多次发生。

如果只需要一次初始化,则可以将其放入构造函数中,并使用两个迭代器向量构造函数:

Foo::Foo(double* w, int len) : w_(w, w + len) { }

否则,请使用先前建议的assign:

void set_data(double* w, int len)
{
    w_.assign(w, w + len);
}

1
就我而言,任务将反复发生。
弗兰克

12

您可以自动“学习”数组的大小:

template<typename T, size_t N>
void set_data(const T (&w)[N]){
    w_.assign(w, w+N);
}

希望您可以如上所述将接口更改为set_data。它仍然接受C样式数组作为其第一个参数。它只是碰巧参考了。


这个怎么运作

[更新:请参阅此处以了解关于尺寸的更全面的讨论]

这是一个更通用的解决方案:

template<typename T, size_t N>
void copy_from_array(vector<T> &target_vector, const T (&source_array)[N]) {
    target_vector.assign(source_array, source_array+N);
}

这是可行的,因为该数组将作为对数组的引用传递。在C / C ++中,您不能将数组作为函数传递,而是将其衰减为指针,并且会丢失大小。但是在C ++中,您可以将引用传递给数组。

通过引用传递数组要求类型完全匹配。数组的大小是其类型的一部分。这意味着我们可以使用模板参数N为我们学习尺寸。

具有返回向量的函数可能更简单。启用适当的编译器优化后,这应该比看起来快。

template<typename T, size_t N>
vector<T> convert_array_to_vector(const T (&source_array)[N]) {
    return vector<T>(source_array, source_array+N);
}

1
在过去的样品,return { begin(source_array), end(source_array) };也有可能
MM

12

好的,Pavel接近了,但是还有一个更简单,更优雅的解决方案,可以从ac样式数组初始化顺序容器。

在您的情况下:

w_ (array, std::end(array))
  • 数组将为我们提供指向数组开头的指针(未捕获其名称),
  • std :: end(array)将使我们有一个到数组末尾的迭代器。

1
这需要什么C ++的包含/版本?
弗拉德(Vlad)2015年

1
从至少c ++ 98开始,这是std :: vector的构造函数之一。它被称为“范围构造函数”。cplusplus.com/reference/vector/vector/vector尝试一下。
Mugurel

1
更独立的版本是:w_(std :: begin(array),std :: end(array)); (将来您可以更改C ++容器的C数组)。
Andrew Romanov

13
请注意,这仅在具有实数array(通常意味着要从全局或局部(在当前函数中声明)数组进行复制)的情况下才有效。在OP的情况下,他正在接收一个指针和一个长度,并且由于未在长度上进行模板化,因此他们无法更改为接收指向大小数组或任何数组的指针,因此std::end将无法工作。
ShadowRanger 2016年

2
vector不会重载operator(),因此不会编译。std::end在指针上调用也没有用(该问题要求从指针和单独的length变量分配向量)。它将改善您的答案,以显示有关您要提出的建议的更多背景信息
MM

2

快速的通用答案:

std::vector<double> vec(carray,carray+carray_size); 

或特定问题:

std::vector<double> w_(w,w+len); 

基于以上内容不要忘记可以将指针视为迭代器


0

std::vector<double>::assign是要走的路,因为它很少的代码。但是实际上它是如何工作的?它不调整大小然后复制吗?在STL的MS实现中,我正在使用它。

恐怕没有更快的方法来实现(重新)初始化您的std::vector


如果要在向量和数组之间共享数据怎么办?在这种情况下,我们需要复制任何内容吗?
弗拉德(Vlad)2015年

那是答案还是问题?它给已经存在的答案带来了什么?
让·弗朗索瓦·法布尔

@Jean-FrançoisFabre,您的评论带来了什么?;)是的,这是很久以前给出的答案。
Janusz Lenar 18/09/17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.