我正在用C++中的向量进行一些实验.我正在使用的代码如下
#include <vector>
#include <iostream>
int main()
{
std::vector<float> aVector = std::vector<float>(10); // IMPORTANT LINE
std::cout << "Vector size: " << aVector.size() << std::endl;
aVector.clear();
aVector[0] = 2.2;
std::cout << "Vector size: " << aVector.size() << std::endl;
aVector.push_back(0.1);
std::cout << "Vector size: " << aVector.size() << std::endl;
aVector.clear();
std::cout << "Vector size: " << aVector.size() << std::endl;
aVector[0] = 2.1;
std::cout << "Vector size: " << aVector.size() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我有向量,用N个元素初始化它,然后清除向量并尝试放置赋值aVector[0] = 1.1,程序一直到最后没有分段错误.
另一方面,如果我创建一个向量但是没有传递初始元素的数量,那么当尝试使用aVector[0] = 1.1它来赋值时,会使程序崩溃.
出现分段错误的唯一方法是因为我试图写入无效的内存地址.因此,根据我的理解,创建向量而不是初始化意味着指向实际向量数据的指针指向无处,而初始化向量和清除时保持指向已分配内存的指针,但向量的大小仅缩小为0?这是否意味着即使在清除了一个向量之后,之前存储的值仍然存在?
这是规范中定义的行为吗?我希望清除擦除并释放以前分配的内存.
向量分配的内存不限于向量使用的内存.让我们一步一步地完成这个程序.请注意,我将描述实际发生的事情 ; 正式地,当你尝试写入aVector[0]时,aVector.size()==0无论你最初是否分配了任何元素,你都会调用未定义的行为):
std::vector<float> aVector = std::vector<float>(10); // IMPORTANT LINE
Run Code Online (Sandbox Code Playgroud)
在这里初始化向量,默认初始化10个元素.也就是说,它为10个浮点数分配空间,并将每个浮点数初始化为零.内存现在看起来像这样:
+-------+-----+-------------+
| begin | end | capacity=10 |
+-------+-----+-------------+
| |
| \----------------------------------------------------\
| |
V V
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
Run Code Online (Sandbox Code Playgroud)
容量告诉您已分配了多少个单元.
请注意BTW你刚才可以写的 std::vector<float> aVector(10);
你现在做
std::cout << "Vector size: " << aVector.size() << std::endl;
Run Code Online (Sandbox Code Playgroud)
该功能std::vector<>::size()只是计算之间的差异begin和end.因此10,对于begin和之间的10个元素,你得到了end.
aVector.clear();
Run Code Online (Sandbox Code Playgroud)
这会重置end为等于begin并销毁超出新端的所有对象(float通常意味着什么都不做;但是调试版本可能会例如用NaN覆盖浮点数).也就是说,你的矢量现在看起来像这样:
+-------+-----+-------------+
| begin | end | capacity=10 |
+-------+-----+-------------+
| |
|/-----/
|
V
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| ??? | ??? | ??? | ??? | ??? | ??? | ??? | ??? | ??? | ??? |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
Run Code Online (Sandbox Code Playgroud)
你看,记忆依旧存在.
aVector[0] = 2.2;
Run Code Online (Sandbox Code Playgroud)
由于std::vector<>::operator[]不进行范围检查(尽管调试版本可以执行它们),这会导致指向浮点数的赋值begin.因为即使当前没有初始化浮点数也可以分配(如果你有例如a std::vector<std::string>,情况会有所不同),这个任务成功了,你现在有了
+-------+-----+-------------+
| begin | end | capacity=10 |
+-------+-----+-------------+
| |
|/-----/
|
V
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 2.2 | ??? | ??? | ??? | ??? | ??? | ??? | ??? | ??? | ??? |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
Run Code Online (Sandbox Code Playgroud)
下一个,
std::cout << "Vector size: " << aVector.size() << std::endl;
Run Code Online (Sandbox Code Playgroud)
当然会放弃0,因为这之间的区别begin和end.
aVector.push_back(0.1);
Run Code Online (Sandbox Code Playgroud)
该成员push_back将首先检查是否存在其他元素的空间end(在这种情况下显然是这样),如果不存在则重新分配(现在不适用),然后简单地构造该值的新对象*end并增加end.所以现在你的矢量看起来像这样:
+-------+-----+-------------+
| begin | end | capacity=10 |
+-------+-----+-------------+
| |
| //
| |
V V
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 0.1 | ??? | ??? | ??? | ??? | ??? | ??? | ??? | ??? | ??? |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,对于矢量,您2.2实际上并不存在,因此它被新构造的覆盖0.1.
由于程序的其余部分只是重复前面的步骤(结果相同),我在这里停下来.
现在如果在开始时你没有请求任何元素,则向量最初不会分配内存,因此尝试写入aVector[0]将导致分段错误.
| 归档时间: |
|
| 查看次数: |
4258 次 |
| 最近记录: |