简体   繁体   English

为什么在 C++ 中的向量上使用索引运算符被认为是不好的风格?

[英]Why is it considered bad style to use the index operator on a vector in C++?

I am working on a program that uses vectors.我正在开发一个使用向量的程序。 So the first thing I did was declare my vector.所以我做的第一件事就是声明我的向量。

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

(BTW, is this also considered bad practice? Should I just type std::vector<double> x(10) ?) (顺便说一句,这也被认为是不好的做法吗?我应该只输入std::vector<double> x(10)吗?)

Then I proceeded to assign values to the vector, and ask for its size.然后我继续为向量赋值,并询问它的大小。

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

I didn't know it would return 0 , so after some searching I found out that I needed to use the push_back method instead of the index operator.我不知道它会返回0 ,所以经过一些搜索我发现我需要使用 push_back 方法而不是索引运算符。

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

And now it returns 10 .现在它返回10

So what I want to know is why the index operator lets me access the value "stored" in vector x at a given index, but wont change its size.所以我想知道的是为什么索引运算符让我访问向量x中给定索引处“存储”的值,但不会改变它的大小。 Also, why is this bad practice?另外,为什么这是不好的做法?

When you do x.reserve(10) you only set the capacity to ten elements, but the size is still zero.当您执行x.reserve(10)您只将容量设置为十个元素,但大小仍然为零。

That means then you use the index operator in your loop you will go out of bounds (since the size is zero) and you will have undefined behavior .这意味着然后您在循环中使用索引运算符,您将越界(因为大小为零)并且您将具有未定义的行为

If you want to set the size, then use either resize or simply tell it when constructing the vector:如果要设置大小,请使用resize或在构造向量时简单地告诉它:

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

As for the capacity of the vector, when you set it (using egreserve ) then it allocates the memory needed for (in your case) ten elements.至于向量的容量,当您设置它(例如使用reserve )时,它会分配(在您的情况下)十个元素所需的内存。 That means when you do push_back there will be no reallocations of the vector data.这意味着当您执行push_back ,将不会重新分配矢量数据。

If you do not change the capacity, or add elements beyond the capacity, then each push_back may cause a reallocation of the vector data.如果不改变容量,或者添加超出容量的元素,那么每次push_back可能导致矢量数据的重新分配。

It sounds like you're asking why things are the way they are.听起来你在问为什么事情是这样的。 Most of it is down to efficiency.大部分都归结为效率。

If x[i] were to create value if it didn't already exist, there would be two hits to efficiency.如果x[i]在不存在的情况下创造价值,那么效率将受到两次打击。 First, the caller of indexing operations should ensure the index is not beyond the current size of the vector.首先,索引操作的调用者应确保索引不超过向量的当前大小。 Second, the new element would need to be default constructed even if you're about to assign a new value into it anyway.其次,即使您要为其分配新值,也需要默认构造新元素。

The reason for having both reserve and resize is similar. reserveresize的原因是相似的。 resize requires a default construction of every element. resize需要每个元素的默认构造。 For something like vector<double> that doesn't seem like a big deal, but for vector<ComplicatedClass> , it could be a big deal indeed.对于像vector<double>这样的东西来说,这似乎没什么大不了的,但对于vector<ComplicatedClass> ,这确实可能是一件大事。 Using reserve is an optimization, completely optional, that allows you to anticipate the final size of the vector and prevent reallocations while it grows.使用reserve是一种完全可选的优化,它允许您预测向量的最终大小并防止在其增长时重新分配。

push_back avoids the default construction of an element, since the contents are known, it can use a move or copy constructor. push_back避免了元素的默认构造,因为内容是已知的,它可以使用移动或复制构造函数。

None of this is the wrong style, use whatever's appropriate for your situation.这都不是错误的风格,使用适合您情况的任何方式。

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

BTW, is this also considered bad practice?顺便说一句,这也被认为是不好的做法吗?

No, creating an empty vector and reserving memory is not a bad practice.不,创建一个空向量并保留内存并不是一个坏习惯。

Should I just type std::vector<double> (10) ?)我应该只输入std::vector<double> (10)吗?)

If your intention is to initialize the vector of 10 elements, rather than empty one, then yes you should.如果您的意图是初始化 10 个元素的向量,而不是空一个,那么是的,您应该这样做。 (If your intention is to create an empty vector, then no) (如果您的目的是创建一个空向量,则否)

Then I proceeded to assign values to the vector, and ask for its size.然后我继续为向量赋值,并询问它的大小。

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

This has undefined behaviour.这具有未定义的行为。 Do not try to access objects that do not exist.不要尝试访问不存在的对象。

so after some searching I found out that I needed to use the push_back method instead of the index operator.所以经过一番搜索后,我发现我需要使用 push_back 方法而不是索引运算符。

That is one option.那是一种选择。 Another is to use the constructor to initialize the elements: std::vector<double> (10) .另一种方法是使用构造函数来初始化元素: std::vector<double> (10) Yet another is to use std::vector::resize .另一种是使用std::vector::resize

Why is it considered bad style to use the index operator on a vector in C++?为什么在 C++ 中的向量上使用索引运算符被认为是不好的风格?

It is not in general.它不是一般的。 It is wrong (not just bad style) if there are no elements at the index that you try to access.如果您尝试访问的索引中没有元素,那是错误的(不仅仅是糟糕的样式)。

Should I just type std::vector<double> x(10) ?我应该只输入std::vector<double> x(10)吗?

Definitely yes!绝对是的!

As mentioned in @Some programmer dude's answer std::vector::reserve() only affects allocation policies but not the size of the vector.正如@Some 程序员兄弟的回答中提到的那样, std::vector::reserve()只影响分配策略,而不影响向量的大小。

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

is actually equivalent to实际上相当于

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

The bracket operator of the std::vector lets you access an item at the index i in your vector. std::vector的括号运算符允许您访问std::vector索引i处的项目。 If an item i does not exist, it cannot be accessed, neither for writing nor for reading.如果项i不存在,则无法访问它,无论是写入还是读取。

So what I want to know is why the index operator lets me access the value "stored" in vector x at a given index, but wont change its size.所以我想知道的是为什么索引运算符让我访问向量 x 中给定索引处“存储”的值,但不会改变它的大小。

Because it wasn't designed to work that way.因为它不是为了那样工作而设计的。 Probably the designers did not think that this behaviour would be desirable.可能设计者不认为这种行为是可取的。

Please also note that std::vector::reserve does reserve memory for the vector but does not actually change its size.另请注意, std::vector::reserve确实为向量保留了内存,但实际上并未更改其大小。 So after calling x.reserve(10) your vector has still got a size of 0 although internally memory for 10 elements has been allocated.因此,在调用x.reserve(10)之后,尽管已分配了 10 个元素的内部内存,但您的向量的大小仍为0 If you now want to add an element, you must not use the bracket operator but std::vector::push_back instead.如果您现在要添加元素,则不得使用方括号运算符,而应使用std::vector::push_back This function will increase the vector's size by one and then append your item.此函数会将向量的大小增加 1,然后附加您的项目。 The advantage of calling reserve is that the memory for the vector must not be reallocated when calling push_back multiple times.调用reserve的好处是多次调用push_back时不能重新分配vector 的内存。

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

I think the behaviour you desire could be achieved using std::vector::resize .我认为可以使用std::vector::resize实现您想要的行为。 This function reserves the memory as reserve would and then actually changes the size of the vector.这个函数会像reserve一样reserve内存,然后实际改变向量的大小。

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

The previous code is equivalent to:前面的代码等价于:

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

Here the size is the constructor argument.这里的大小是构造函数参数。 Creating the vector this way performs the resize operation on creation.以这种方式创建vector会在创建时执行调整大小操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM