c++ - c ++:清除向量的向量似乎将向量元素留在原处
问题描述
这被标记为重复,因为它声称它已经在这里得到了回答。我觉得我的问题根本没有得到回答,因为那篇文章根本不涉及向量或类似的容器。对我的问题的评论也没有回答。因此,基于我将问题埋得太深的理论,我会在我的例子之前把它放在前面。
当我们在向量上调用 .clear() 时,它会在向量的每个元素上调用析构函数。“众所周知”的例外是当它是指针向量时。我下面的示例表明,当我们 .clear() 一个向量向量时,析构函数显然不会在作为其元素的向量上被调用,因为之后我仍然可以访问它们。为什么?向量以什么方式“有点像”指针,以便不会调用析构函数?
要清楚一些事情:
我知道向量不是指针。但是我不太清楚向量的“胆量”到底是什么样的,这可能就是我不明白这一点的原因。
另外,我知道这是未定义的行为。我的问题是,为什么它是未定义的?我希望这会导致明确的错误,而不是未定义的行为。我通常希望当我做一些愚蠢的事情时,编程语言应该踢我的屁股。在这里,C++ 没有惩罚我做一些非常愚蠢的事情,我很好奇为什么。(是的,我知道 C++ 标准的制定者无法预测像我这样的程序员可能会做的每一件愚蠢的事情,我们有责任不做傻事。但是在 a 之后这些向量的持续可访问性
.clear()
是非常违反直觉的。)
它出现是因为在一个很长的程序中出现了意外行为,我将问题追溯到这个。我修复了它,但仍然对为什么该程序巧妙地失败而不是壮观地失败感到困惑。
好的,这是原始问题:
这里还有一些与此相关的其他问题,例如这个和这个,但我认为它们并不能完全解决我想知道的问题。我的理解是,在向量上调用 clear 会在向量的每个元素上调用析构函数(但请参阅下面的例外情况)。因此,对于向量的向量,我会假设析构函数将在向量向量中的每个向量上调用。这似乎是不正确的。我知道几种编写代码来处理它的方法。但是我仍然对这种行为感到有些困惑。此代码显示了行为:
using namespace std;
#include <iostream>
#include <vector>
void writeMat(vector<vector<double>> &vec);
int main()
{
vector<vector<double>> b;
writeMat(b);
// Trying to get b[0].size() here results in a core dump, as expected.
vector<double> btry1 = {1.0, 2.0};
vector<double> btry2 = {3.0, 4.0};
b.push_back(btry1);
b.push_back(btry2);
cout << "Added some stuff to the vector." << endl;
writeMat(b);
b.clear();
cout << "Cleared the vector. Now it is: " << endl;
writeMat(b);
cout << "But final check... b.size() = " << b.size() << " and b[0].size() = " << b[0].size() << endl;
return 0;
}
void writeMat(vector<vector<double>> &vec)
{
cout << "vec.size() = " << vec.size() << endl;
for (int i = 0; i < vec.size(); i++)
{
cout << "vec[" << i << "].size() = " << (vec[0]).size() << endl;
}
cout << "vec is: " << endl << "--------------------" << endl;
for (int i = 0; i < vec.size(); i++)
{
for (int j = 0; j < vec[i].size(); j++)
{
cout << vec[i][j] << " ";
}
cout << endl;
}
cout << "--------------------" << endl;
}
生成输出:
vec.size() = 0
vec is:
--------------------
--------------------
Added some stuff to the vector.
vec.size() = 2
vec[0].size() = 2
vec[1].size() = 2
vec is:
--------------------
1 2
3 4
--------------------
Cleared the vector. Now it is:
vec.size() = 0
vec is:
--------------------
--------------------
But final check... b.size() = 0 and b[0].size() = 2
我希望在调用b[0].size()
之后调用b.clear()
会导致核心转储,就像我在将任何元素添加到 b 之前调用它一样。但相反,它返回值 2,这表明虽然b.size()
现在为零,但b[0]
仍然在内存中徘徊。确实,修改上面的代码我发现,之后b.clear()
,还是会报,比如,b[0][1]
就是2。
我在这里看到,对于像这样的向量vector<MyClass>
,在调用时会在向量的每个元素上调用析构函数,clear()
但对于像这样的指针向量vector<MyClass*>
则不会。所以我猜一个向量在某种程度上与一个指针“更相似”,而不是一个对象。对我来说,像向量这样的容器与更原始的类型有什么关系,我从来都不是很清楚。我认为向量是一个旧式数组(不是 std::array,一个像我们在 20 年前在 C 中使用的旧数组......)具有相当薄的方法包装以使其更友好。但这并不完全正确,因为将指针传递给向量与将指针传递给数组具有非常不同的效果。
所以,我想我的问题大致是这样的:向量不是指针。但是当清除向量向量时,行为似乎类似于清除指针向量。那么导致这种行为的相似性是什么?我意识到这很可能会深入了解为向量预留的内存块的外观,而不是为数组预留的内存块的外观。
我突然想到这可能特定于 C++ 的实现。我在 Linux 操作系统中使用 g++。
解决方案
推荐阅读
- excel - 使用 VBA 进行扩展编程
- javascript - Moment.js format() 返回随机时间字符串
- python - 如果它们以相同的字符集开头,Python如何提取所有列表元素
- hl7-fhir - FHIR 使用 _content 搜索多个单词
- razorsql - 如何在两个直管“||”之间提取字符串 在 RazorSQL 中
- c# - 如何在较小的图像中找到图像
- mongoose - Mongoose 在填充数组中填充
- javascript - Ajax request: undefined
- python - 曼哈顿和错位启发式
- java - 使用 JAVA 表格 API 识别 Google 表格中的单元格类型(公式、列表等)