【问题标题】:Why is it possible to access vectors created inside a for loop that are saved to a vector of vectors?为什么可以访问在 for 循环中创建并保存到向量向量中的向量?
【发布时间】:2019-07-14 00:55:29
【问题描述】:

我一直在试验 C++ 的向量容器,并注意到当我使用向量的向量并在 for 循环中创建向量并将其推回给它时,我仍然能够访问在for循环。

我尝试用谷歌搜索它,但只在 C++ 中遇到了我不太了解的移动操作的提及。作为一名 C 程序员,当我尝试访问在堆栈上创建的向量时,我预计会出现分段错误,这些向量超出了下面代码中 for 循环的范围。有人可以在这里向我解释 C++ 在后台做什么吗?这怎么可能?

#include <iostream>
#include <vector>

using namespace std;

void display (const vector<vector<int> >& tdv) {
    for (int i = 0; i < tdv.size(); i++) {
        for (int j = 0; j <tdv[i].size(); j++) {
            cout << " " << tdv[i][j];
        }
        cout << endl;
    }
}

int main () {
    vector<vector<int> > vov;
    for (int i = 1; i < 5; ++i) {
        vector<int> vec(i, i);
        vov.push_back(vec);
    }
    display (vov);
    return 0;
}

当我运行代码时,我得到以下输出:

 1
 2 2
 3 3 3
 4 4 4 4

【问题讨论】:

  • 作为一名 C 程序员,当我尝试访问向量时,我预计会出现分段错误 -- 作为一名 C 程序员,你知道你可以返回并按值传递structC 没有问题?这是相同的概念,只是 C++ 使用构造函数和析构函数的概念将其扩展到其他类型。
  • 任何类型的程序员都不会期望出现段错误。这是一个愚蠢的赌注,有时一个错误的指针指向有效的内存,你不会得到一个段错误。系统可能没有回收坏指针使用的内存,不会出现段错误。有时内存很快被同一程序的其他部分重用,而您不会遇到段错误。您可能没有收到段错误的原因有很多。
  • Segfaults 很糟糕,当你没有预料到它们时,它们却能避免没有得到 segfault 和代码践踏程序其他部分拥有的有效内存或写入的代码它曾经拥有数小时、数天或数年的内存,直到某些东西扰乱系统并且程序最终确实出现了段错误。墨菲定律说这将是一个糟糕的时期。就像机长打开飞机的自动驾驶仪时一样。
  • @user4581301 你是对的。我应该更加小心预期段错误。谢谢你的解释:)

标签: c++ vector scope c++-standard-library


【解决方案1】:

向量的行为不像引用/指针/迭代器类型。它们不是指其他人拥有的对象。他们拥有自己的缓冲区,并且该缓冲区没有其他所有者,并且他们在整个生命周期内都保持该缓冲区处于活动状态。

Vector 是一种值类型。当你创建一个向量的副本时,你会得到一个包含元素副本的新动态数组。向量的副本与原始向量的引用不同。

vector<int> vec(i, i);

这是一个局部变量。向量在动态内存中分配一个缓冲区。

vov.push_back(vec);

这会在向量向量的缓冲区内创建一个向量对象的副本。副本有自己的动态缓冲区。

局部变量在迭代结束时被销毁,但副本继续存在于向量的向量中。而且由于每个向量都有自己独特的缓冲区,因此活向量的缓冲区不受其他向量被破坏的影响。

【讨论】:

  • 澄清每个向量如何拥有自己独特的缓冲区以及它们如何不像指针那样表现真的很有帮助。我不知道本地向量被复制到向量向量的缓冲区中。非常感谢您的详细解释:)
【解决方案2】:

push_back() 将其参数的副本添加到向量中。

    vector<int> vec(i, i);
    vov.push_back(vec);

这会创建一个临时的vec 对象,是的。它将对该对象的引用传递给push_back() 方法,该方法将该对象的副本添加到向量中(如果需要,重新分配向量中的所有内容)。

之后临时对象被销毁,但没关系。它的副本现在存在于向量中。

向量拥有它所包含的所有对象。无论使用何种方式向向量添加某些内容,对象都会被复制/移动/任何内容到向量中,并且向量拥有它。这就是矢量的工作原理。

当向量被销毁时,向量中的所有对象都会随之销毁。

大多数介绍性 C++ 书籍通常都有一些练习练习,用于使用类 C 原语实现类向量对象。研究这些章节可能会提供丰富的信息。

【讨论】:

  • 非常感谢您的解释。可以复制/移动局部向量是有道理的。我一定会查看一些 C++ 书籍,以找到可以让我使用类 C 原语实现类向量对象的练习 :)
  • 所有向量,无论是本地的还是其他的,都可以被复制或移动。 C++ 库中的每个容器都实现了一个复制/移动操作,该操作将容器的内容连同它一起复制/移动。
  • @SamVarshavchik 更准确地说:const 向量不能被移动,包含不可复制元素的向量不能被复制。
【解决方案3】:

向量的空间是在堆上分配的,而不是在栈上。向量构造函数分配空间,向量析构函数释放它。

这是 C++ 的标准。构造函数和析构函数给你很大的力量。

【讨论】:

    猜你喜欢
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-20
    • 1970-01-01
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多