向2D矢量添加矢量,并保持对最后一个矢量的引用

时间:2015-09-15 10:01:05

标签: c++

我正在编写一个程序,并且有一个很难识别的非常微妙的错误。

我对这个程序进行了几个小时的检查,看起来这是因为我在resize()中分配新的vector而误用了vector,因为我误用了back() vector,或更新参考变量。

我写了一个更简单的代码,在我原来的演示程序中包含类似的问题:

int main() {

    vector<vector<int>> A(1);
    vector<int> &recent = A.back();

    recent.emplace_back(50);
    cout << A.back()[0] << endl; //prints 50

    A.resize(2);
    A[1] = vector<int>();
    cout << A.size() << endl;    //prints 2
    recent = A.back();
    cout << A[1].size() << endl; //prints 0
    recent.emplace_back(20);     //Segmentation fault occurs!!
    cout << A[1][0] << endl;
}

当我尝试emplace_back(20)时发生分段错误,虽然在我的原始程序中它不会抛出任何错误,也不会emplace该元素。

可能的问题原因,在我看来是:

  1. 我使用resize()在2D向量vector的当前最后位置之后分配新的A,因为我不知道如何emplace_back()一个空向量
  2. 2,3。在recent = A.back();中,我不确定我是否正确更新了引用变量(定义为vector<int> &recent),如果back()给出正确的引用在2D向量A的末尾新分配的向量。

    逻辑看起来非常好,但显然我做错了。

    我做错了什么,我该怎么办呢?

3 个答案:

答案 0 :(得分:3)

C ++中的引用无法“更新”。对resize的调用可能(并且可能会)使对向量的原始内容的任何引用无效。因此recentA.resize(2);之后的悬空参考。

在此处创建初始A

std::vector<std::vector<int>> A(1);

外部向量需要能够存储一个单一的向量。 如果您向std::vector<int>添加另一个A,则A的第一个元素可能会移动到另一个内存位置。由于recent将始终引用旧的内存位置,因此您会看到段错误。

有关矢量的工作原理,请参阅“c++ Vector, what happens whenever it expands/reallocate on stack?”。

关于如何规避这个问题: 如果您事先知道向量的大小,则可以使用reserve来阻止向量A重新分配其内容。然而,您仍然面临无法“重新分配”引用的问题。您始终可以使用A.back()来引用最后一个元素。

您可以使用一个带参考参数的函数,该参数将在调用函数时绑定:

void do_stuff(std::vector<int> & recent)
{
  // do stuff with recent
}

std::vector<std::vector<int>> A;
while (condition)
{
  // add whatever to A
  A.emplace_back(std::vector<int>{});
  // do stuff with last element
  do_stuff(A.back());
}

另一种方法是使用scope

std::vector<std::vector<int>> A(1);
{
  std::vector<int> &recent = A.back();
  recent.emplace_back(50);
  std::cout << A.back()[0] << std::endl; //prints 50
  A.resize(2);
} // recent goes out of scope here

std::cout << A.size() << std::endl;    //prints 2
{
  std::vector<int> &recent = A.back(); // another recent indepedant of first one
  std::cout << A[1].size() << std::endl; //prints 0
  recent.emplace_back(20); 
  std::cout << A[1][0] << std::endl;  // prints 20
}

答案 1 :(得分:3)

让我们逐行逐步完成代码。

vector<vector<int>> A(1);
vector<int> &recent = A.back();

在这里,我们创建一个vector,其中包含一个默认构造的vector<int>作为其内容。然后,我们将引用绑定到最后一个唯一元素。

recent.emplace_back(50);
cout << A.back()[0] << endl; //prints 50

我们现在将50放入唯一的矢量并打印出来。

A.resize(2);

现在我们调整vector的大小。如果需要重新分配空间,所有迭代器,指针和对内容的引用现在都是无效的

A[1] = vector<int>();
cout << A.size() << endl;    //prints 2

这很好,因为A中有足够的空间。

recent = A.back();

<强> BANG

此作业不重新绑定recent,它会尝试将A.back()指定给引用者。如果为A重新分配空间,recent不再是有效的引用,那么我们将进入未定义行为的范围。

老实说,直接使用A.back()而不是保持对它的引用可能是你最好的选择。如果你绝对想要对结尾持有某种引用,那么这是合理使用非拥有指针。

答案 2 :(得分:2)

根据评论中的讨论,您的原始问题似乎是:

<label for="">Click to see differences</label>
<input type="checkbox" class="check-diff">
<div class="compare-diff">
    <div class="row">
        <div class="col-sm-3 title">Name</div>
        <div class="col-sm-3">John</div>
        <div class="col-sm-3">Henry</div>
        <div class="col-sm-3">Kim</div>
    </div>
    <div class="row checkDiff">
        <div class="col-sm-3 title">Status</div>
        <div class="col-sm-3 diff">Single</div>
        <div class="col-sm-3 diff">Married</div>
        <div class="col-sm-3 diff">Single</div>
    </div>
    <div class="row checkDiff">
            <div class="col-sm-3 title">Car</div>
            <div class="col-sm-3 diff">Yes</div>
            <div class="col-sm-3 diff">Yes</div>
            <div class="col-sm-3 diff">Yes</div>
    </div>
    <div class="row checkDiff">
            <div class="col-sm-3 title">Kids</div>
            <div class="col-sm-3 diff">Yes</div>
            <div class="col-sm-3 diff">Yes</div>
            <div class="col-sm-3 diff">No</div>
    </div>
    <div class="row checkDiff">
            <div class="col-sm-3 title">Home</div>
            <div class="col-sm-3 diff">Yes</div>
            <div class="col-sm-3 diff">Yes</div>
            <div class="col-sm-3 diff">Yes</div>
    </div>
</div>

并且你想要一个简写符号来访问它的最后一个元素:

vector<vector<int>> very_long_name_that_cannot_be_changed;

这是防止调整大小的证明,因为引用只跟踪向量,而不是它的最后一个元素。