为什么在 C++ 中对向量使用索引运算符被认为是不好的风格?
Why is it considered bad style to use the index operator on a vector in C++?
我正在开发一个使用向量的程序。所以我做的第一件事就是声明我的向量。
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;
我不知道它会 return 0
,所以经过一些搜索我发现我需要使用 push_back 方法而不是索引运算符。
for (int i=0; i<10; i++)
{
x.push_back(7.1);
}
std::cout<<x.size()<<std::endl;
现在 returns 10
。
所以我想知道的是为什么索引运算符允许我在给定索引处访问向量 x
中的值 "stored",但不会更改其大小。另外,为什么这是不好的做法?
当您执行 x.reserve(10)
时,您仅将 capacity 设置为十个元素,但 size 仍为零。
这意味着您在循环中使用索引运算符会越界(因为大小为零)并且您将有 未定义的行为.
如果要设置大小,请使用 resize
或在构造向量时简单地告诉它:
std::vector<double> x(10);
至于向量的容量,当你设置它时(使用例如reserve
)然后它分配(在你的情况下)十个元素所需的内存.这意味着当您执行 push_back
时,将不会重新分配矢量数据。
如果不改变容量,或者添加超出容量的元素,那么每次push_back
都可能导致向量数据的重新分配。
std::vector<double> x;
x.reserve(10)
BTW, is this also considered bad practice?
不,创建一个空向量并保留内存并不是一个坏习惯。
Should I just type std::vector<double> (10)
?)
如果您打算初始化包含 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;
这有未定义的行为。不要尝试访问不存在的对象。
so after some searching I found out that I needed to use the push_back method instead of the index operator.
这是一种选择。另一种是使用构造函数来初始化元素:std::vector<double> (10)
。另一种是使用 std::vector::resize
.
Why is it considered bad style to use the index operator on a vector in C++?
不是一般的。如果您尝试访问的索引处没有元素,这是错误的(不仅仅是糟糕的风格)。
Should I just type std::vector<double> x(10)
?
当然可以!
如中所述std::vector::reserve()
仅影响分配策略,但不影响向量的大小。
std::vector<double> x(10);
实际上等同于
std::vector<double> x;
x.resize(10);
std::vector
的括号运算符允许您访问向量中索引 i
处的项目。如果项目 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.
因为它不是为那样工作而设计的。可能设计者并不认为这种行为是可取的。
另请注意,std::vector::reserve
确实为向量保留了内存,但实际上并没有改变它的大小。因此,在调用 x.reserve(10)
之后,尽管已分配了 10 个元素的内部内存,但您的向量的大小仍然为 0
。如果现在要添加元素,则不能使用括号运算符,而应使用 std::vector::push_back
。此函数会将向量的大小增加一,然后附加您的项目。调用reserve
的好处是多次调用push_back
时,vector的内存不必重新分配。
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;
前面的代码等同于:
std::vector<double> x(3);
x[0] = 3;
x[1] = 1;
x[2] = 7;
这里的大小是构造函数的参数。以这种方式创建 vector
会在创建时执行调整大小操作。
听起来你在问为什么事情是这样的。大部分取决于效率。
如果 x[i]
要创造尚不存在的价值,那么效率将受到两次打击。首先,索引操作的调用者应确保索引不超过当前向量的大小。其次,即使您要为其分配新值,新元素也需要默认构造。
同时拥有 reserve
和 resize
的原因是相似的。 resize
需要每个元素的默认构造。对于像 vector<double>
这样的东西来说,这似乎没什么大不了的,但是对于 vector<ComplicatedClass>
来说,这可能确实是一件大事。使用 reserve
是一种优化,完全可选,它允许您预测向量的最终大小并防止在它增长时重新分配。
push_back
避免了元素的默认构造,因为内容是已知的,它可以使用移动或复制构造函数。
None 这是错误的样式,请使用适合您情况的任何样式。
我正在开发一个使用向量的程序。所以我做的第一件事就是声明我的向量。
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;
我不知道它会 return 0
,所以经过一些搜索我发现我需要使用 push_back 方法而不是索引运算符。
for (int i=0; i<10; i++)
{
x.push_back(7.1);
}
std::cout<<x.size()<<std::endl;
现在 returns 10
。
所以我想知道的是为什么索引运算符允许我在给定索引处访问向量 x
中的值 "stored",但不会更改其大小。另外,为什么这是不好的做法?
当您执行 x.reserve(10)
时,您仅将 capacity 设置为十个元素,但 size 仍为零。
这意味着您在循环中使用索引运算符会越界(因为大小为零)并且您将有 未定义的行为.
如果要设置大小,请使用 resize
或在构造向量时简单地告诉它:
std::vector<double> x(10);
至于向量的容量,当你设置它时(使用例如reserve
)然后它分配(在你的情况下)十个元素所需的内存.这意味着当您执行 push_back
时,将不会重新分配矢量数据。
如果不改变容量,或者添加超出容量的元素,那么每次push_back
都可能导致向量数据的重新分配。
std::vector<double> x; x.reserve(10)
BTW, is this also considered bad practice?
不,创建一个空向量并保留内存并不是一个坏习惯。
Should I just type
std::vector<double> (10)
?)
如果您打算初始化包含 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;
这有未定义的行为。不要尝试访问不存在的对象。
so after some searching I found out that I needed to use the push_back method instead of the index operator.
这是一种选择。另一种是使用构造函数来初始化元素:std::vector<double> (10)
。另一种是使用 std::vector::resize
.
Why is it considered bad style to use the index operator on a vector in C++?
不是一般的。如果您尝试访问的索引处没有元素,这是错误的(不仅仅是糟糕的风格)。
Should I just type
std::vector<double> x(10)
?
当然可以!
如std::vector::reserve()
仅影响分配策略,但不影响向量的大小。
std::vector<double> x(10);
实际上等同于
std::vector<double> x;
x.resize(10);
std::vector
的括号运算符允许您访问向量中索引 i
处的项目。如果项目 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.
因为它不是为那样工作而设计的。可能设计者并不认为这种行为是可取的。
另请注意,std::vector::reserve
确实为向量保留了内存,但实际上并没有改变它的大小。因此,在调用 x.reserve(10)
之后,尽管已分配了 10 个元素的内部内存,但您的向量的大小仍然为 0
。如果现在要添加元素,则不能使用括号运算符,而应使用 std::vector::push_back
。此函数会将向量的大小增加一,然后附加您的项目。调用reserve
的好处是多次调用push_back
时,vector的内存不必重新分配。
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;
前面的代码等同于:
std::vector<double> x(3);
x[0] = 3;
x[1] = 1;
x[2] = 7;
这里的大小是构造函数的参数。以这种方式创建 vector
会在创建时执行调整大小操作。
听起来你在问为什么事情是这样的。大部分取决于效率。
如果 x[i]
要创造尚不存在的价值,那么效率将受到两次打击。首先,索引操作的调用者应确保索引不超过当前向量的大小。其次,即使您要为其分配新值,新元素也需要默认构造。
同时拥有 reserve
和 resize
的原因是相似的。 resize
需要每个元素的默认构造。对于像 vector<double>
这样的东西来说,这似乎没什么大不了的,但是对于 vector<ComplicatedClass>
来说,这可能确实是一件大事。使用 reserve
是一种优化,完全可选,它允许您预测向量的最终大小并防止在它增长时重新分配。
push_back
避免了元素的默认构造,因为内容是已知的,它可以使用移动或复制构造函数。
None 这是错误的样式,请使用适合您情况的任何样式。