c ++:清除向量的向量似乎使向量元素留在原处

时间:2019-07-03 18:19:20

标签: c++ vector destructor

该项目被标记为重复项目,因为据称它已被here答复。我根本不回答我的问题,因为该帖子根本不涉及矢量或类似容器。关于我的问题的任何评论都没有回答。因此,基于我将问题深埋的理论,我将在我的示例之前将其放在前面。

当我们在向量上调用.clear()时,它将在向量的每个元素上调用析构函数。 “众所周知”的例外是当它是指针的向量时。下面的示例表明,当我们清除向量的向量时,显然不会调用作为其元素的向量的析构函数,因为我以后仍然可以访问它们。为什么?向量以何种方式“类似于”指针,以使析构函数不会在其上被调用?

要清楚一些事情:

  • 我知道向量不是指针。但是我不清楚 向量的“内脏”看起来真的很像,这可能就是为什么我 不明白这一点。

  • 此外,我知道这是未定义的行为。 我的问题是,为什么它没有定义?我本来希望 会导致显式错误,而不是不确定的行为。一世 通常希望当我做一些愚蠢的编程时 语言应该踢我屁股。在这里,C ++无法惩罚 我所做的事情很愚蠢,我很好奇为什么。 (是的,我 知道C ++标准的制定者无法预测所有愚蠢的事情 像我这样的程序员可能会做,所以我们的责任是 愚蠢的。但是这些向量在经过 .clear()非常违反直觉。)

它是由于在一个很长的程序中出现意外行为而引起的,因此我将问题追溯到此。我已修复它,但仍然对该程序为何会失败而不是引人注目而感到困惑。

好的,这是原始问题:


这里还有与此相关的其他几个问题,例如this onethis one,但我认为它们并不能完全解决我想知道的问题。我的理解是,在向量上调用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。

我看到here表示,对于像vector<MyClass>这样的向量,调用clear()时会在向量的每个元素上调用析构函数,而对于像{{1} } 它不是。因此,我猜向量在某种程度上与指针“更类似于”而不是对象。对我来说,从来没有很清楚像vector这样的容器与更原始的类型有关。我认为向量是一种旧样式的数组(不是std :: array,就像20年前我们在C语言中使用过的旧数组……),它的包装方法很薄,使其更友好。但这不可能完全正确,因为将指针传递给向量与将指针传递给数组的效果大不相同。

所以,我想我的问题大致是这样的:向量不是指针。但是,当清除向量的向量时,其行为似乎类似于清除指针的向量。那么导致这种行为的相似性是什么?我意识到,这很可能会陷入为向量预留的内存块的外观与数组所预留的内存块的外观截然不同的问题。

在我看来,这个可能特定于C ++的实现。我在Linux操作系统上使用g ++。

0 个答案:

没有答案