为什么在C ++中对向量使用索引运算符被认为是不好的样式?

时间:2017-03-08 15:14:16

标签: c++ vector indexing standard-library push-back

我正在开发一个使用矢量的程序。所以我做的第一件事是声明我的矢量。

std::vector<double> x;
x.reserve(10)

(顺便说一下,这也被认为是不好的做法吗?我应该只输入std::vector<double> x(10)吗?)

然后我继续为矢量赋值,并询问它的大小。

for (int i=0; i<10; i++)
{
    x[i]=7.1;
}
std::cout<<x.size()<<std::endl;

我不知道它会返回0,所以经过一些搜索我发现我需要使用push_back方法而不是索引操作符。

for (int i=0; i<10; i++)
{
    x.push_back(7.1);
}
std::cout<<x.size()<<std::endl;

现在它返回10

所以我想知道的是为什么索引操作符允许我访问值&#34;存储&#34;在给定索引处的向量x中,但不会更改其大小。另外,为什么这是不好的做法?

5 个答案:

答案 0 :(得分:5)

执行x.reserve(10)时,只将容量设置为10个元素,但 size 仍为零。

这意味着你在循环中使用索引运算符将超出界限(因为大小为零)并且你将有未定义的行为

如果您想设置大小,请使用resize或在构造向量时告诉它:

std::vector<double> x(10);

对于向量的容量,当你设置它时(使用例如reserve),它会分配(在你的情况下)十个元素所需的内存。这意味着当你执行push_back时,将不会重新分配矢量数据。

如果您不更改容量或添加超出容量的元素,则每个push_back可能会导致重新分配矢量数据。

答案 1 :(得分:2)

std::vector<double> x;
x.reserve(10)
     顺便说一下,这也被认为是不好的做法吗?

不,创建一个空向量并保留内存并不是一个坏习惯。

  

我应该输入std::vector<double> (10)吗?)

如果你的目的是初始化10个元素的向量,而不是空元素,那么你应该这样做。 (如果你的目的是创建一个空矢量,那么没有)

  

然后我继续为矢量赋值,并询问它的大小。

for (int i=0; i<10; i++)
{
    x[i]=7.1;

这有未定义的行为。不要尝试访问不存在的对象。

  

所以经过一些搜索我发现我需要使用push_back方法而不是索引操作符。

这是一个选择。另一种方法是使用构造函数初始化元素:std::vector<double> (10)。另一个是使用std::vector::resize

  

为什么在C ++中对向量使用索引运算符会被认为是不好的样式?

这不是一般的。如果您尝试访问的索引中没有元素,那么这是错误的(不仅仅是错误的样式)。

答案 2 :(得分:1)

  

我应该输入std::vector<double> x(10)吗?

肯定是的!

@Some programmer dude's answer std::vector::reserve()中所述,仅影响分配政策,但不影响向量的大小。

 std::vector<double> x(10);

实际上相当于

 std::vector<double> x;
 x.resize(10);

答案 3 :(得分:1)

听起来你真的在问为什么事情是这样的。其中大部分都取决于效率。

如果x[i]创建了一个值,如果它还没有存在,那么效率会有两个点击。首先,每个索引操作都需要包含一个检查,以查看它是否超出了向量的当前大小。其次,即使您要为其分配新值,新元素也需要默认构建。

同时拥有reserveresize的原因相似。 resize需要每个元素的默认构造。对于像vector<double>这样看起来不是什么大不了的事,但对于vector<ComplicatedClass>来说,这确实是一件大事。使用reserve是一种完全可选的优化,它允许您预测矢量的最终大小,并防止重新分配的增长。

push_back避免了元素的默认构造,因为已知内容可以使用移动或复制构造函数。

这些都不是坏的风格,根据你的情况使用适合的任何东西。

答案 4 :(得分:0)

std::vector的括号运算符可让您访问向量中索引i的项目。如果项目i不存在,则无法访问,无论是写作还是阅读。

  

所以我想知道的是为什么索引操作符允许我访问值&#34;存储&#34;在给定索引处的向量x中,但不会改变其大小。

因为它没有被设计成以这种方式工作。可能设计师并不认为这种行为是可取的。

请注意std::vector::reserve确实为矢量保留了内存,但实际上并没有改变它的大小。因此,在调用x.reserve(10)之后,您的向量仍然具有0的大小,尽管已经分配了10个元素的内部存储器。如果您现在要添加元素,则不能使用括号运算符,而是使用std::vector::push_back。此功能会将矢量的大小增加1,然后追加您的项目。调用reserve的优点是,多次调用push_back时,不得重新分配向量的内存。

std::vector<double> x;
x.reserve(3);
x.push_back(3);
x.push_back(1);
x.push_back(7);

我认为您希望的行为可以使用std::vector::resize来实现。此函数将内存保留为reserve,然后实际更改向量的大小。

std::vector<double> x;
x.resize(3);
x[0] = 3;
x[1] = 1;
x[2] = 7;

之前的coude相当于:

std::vector<double> x(3);
x[0] = 3;
x[1] = 1;
x[2] = 7;

这里的大小是构造函数参数。以这种方式创建vector会在创建时执行调整大小操作。