【问题标题】:While pushing vector<int> into vector <vector<int> >, SIGABRT - free(): invalid next size (fast) [closed]将向量 <int> 推入向量 <vector<int> > 时,SIGABRT - free():下一个大小无效(快速)[关闭]
【发布时间】:2018-02-16 20:53:11
【问题描述】:

大家好,我正在尝试编写一个函数,它会返回一个 给定向量的所有排列的向量。例如,对于输入 [1,2], 输出应该是 [[1,2], [2,1]]。对于输入 [1,2,3],输出应 为 [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]] .注意 排列的顺序在输出向量中并不重要。

  • 我使用以下逻辑递归生成排列:

    • 函数将向量作为输入,返回向量作为输出。
    • 如果输入向量的大小为1,即输入向量=[int],则输出为[[int]]
    • 其他:
      1. 从输入向量 V 中删除 ELEM = 第一个元素,V' 是删除第一个元素的新向量
      2. 使用递归函数调用查找 V' 的排列。
      3. 对于 permutations(V') 中的每个置换向量,通过在所有可能的位置插入 ELEM 创建一个新的置换向量,并将这个新创建的置换向量附加到要返回的最终输出。
  • 下面是一个测试用例:

    • 输入向量 = [1,2]
    • 预期输出 = [[1,2], [2,1]]
    • 测试用例:
      1. 1被当作ELEM,[2]变成V'
      2. V' i.2 的排列。 [2] 是 [[2]],因为它是递归的基本情况
      3. 然后,对于 permutations(V') 中的每个排列,即对于 [[2]] 中的 [2],我们在 [1,2] 和 [2,1] 的所有位置添加 ELEM 1。这些新创建的排列将被添加到返回排列的最终向量中。

以下是代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

ostream & operator <<(ostream & out, vector<int> printVector) {
    out << "[ ";
    for(int i=0; i<printVector.size();i++) {
        out << printVector[i] << " ";
    }
    out << "]";
    return out;
}
ostream & operator <<(ostream & out, vector< vector<int> > 
printVectorOfVectors) {
    out << "[" << endl;
    for(int i=0; i<printVectorOfVectors.size(); i++) {
        out << printVectorOfVectors[i] << endl;
    }
    out << "]";
    return out;
}

vector< vector<int> > generatePermutations(vector<int> baseVector) {
    if(baseVector.size() == 1) {
        vector< vector<int> > temp;
        temp.push_back(baseVector);

        // DEBUG
        cout << "ROOT CASE , RET PERM : " << endl << temp << endl;
        // \DEBUG

        return temp;
    }
    else {
        vector< vector<int> > temp;
        int elem = baseVector[0];

        baseVector.erase(baseVector.begin());
        // DEBUG
        cout << "ELEM : " << endl << elem << endl;
        cout << "BASE VECTOR : " << endl << baseVector << endl;
        // \DEBUG

        vector< vector<int> > processPermutationsVector = generatePermutations(baseVector);

        // DEBUG
        cout << "PROCESS PERMS : " << endl << processPermutationsVector << endl;
        // \DEBUG

        for(int i=0; i<processPermutationsVector.size(); i++) {
            vector<int> v_i = processPermutationsVector[i];

            // DEBUG
            cout << "V_i : " << endl << v_i << endl;
            // \DEBUG

            for(int k=0; k<v_i.size()+1; k++) {
                vector<int>::iterator it = v_i.begin();
                cout << "k : " << k << endl;
                cout << "ORG PERM : " << endl << v_i << endl;
                v_i.insert(it+k, elem);
                cout << "PUSH PERM : " << endl << v_i << endl;
                temp.push_back(v_i);
                cout << "RET PERMS : " << endl << temp << endl;                    
                v_i.erase(it+k);
                cout << "CLEANED PERM : " << endl << v_i << endl;

            }
        }
        return temp;
    }
}

int main() {
    vector<int> testVector{1,2};
    cout << "TEST VECTOR : " << endl << testVector << endl;

    vector< vector<int> > testPermutationsVector = generatePermutations(testVector);
    cout << "TEST PERMUTATIONS VECTOR" << endl << testPermutationsVector << endl;

    return 0;
}

代码给出以下输出:

TEST VECTOR : 
[ 1 2 ]
ELEM : 
1
BASE VECTOR : 
[ 2 ]
ROOT CASE , RET PERM : 
[
[ 2 ]
]
PROCESS PERMS : 
[
[ 2 ]
]
V_i : 
[ 2 ]
k : 0
ORG PERM : 
[ 2 ]
PUSH PERM : 
[ 1 2 ]
RET PERMS : 
[
[ 1 2 ]
]
CLEANED PERM : 
[ 2 ]
k : 1
ORG PERM : 
[ 2 ]
PUSH PERM : 
[ 2 1 ]
RET PERMS : 
[
[ ]
[ 2 1 ]
]
CLEANED PERM : 
[ 2 ]
double free or corruption (out)

在 codechef online c++ ide 上执行的代码给出了 SIGABRT 的运行时错误 - `./prog' 中的错误:free(): invalid next size (fast)。 新创建的排列未插入向量“temp”的向量中。请帮忙。

【问题讨论】:

  • 你需要调试你的代码,我们不会为你做这个。
  • 由于我在做一个在线ide,所以我使用cout语句来调试。 “RET PERMS”语句打印出最终向量的内容,即使在推送排列之后也是空的。
  • 您的函数generatePermutations 无法正确处理空向量。它会导致未定义的行为。你的printVectorOfVectors[0] 应该是printVectorOfVectors[i]
  • 您只能使用在线 IDE 到此为止(而且这不是很远)。我建议您下载并安装合适的 IDE。
  • @ccpak 打印诊断通常是一个好的开始。另一个有用的工具:onlinegdb.com 这使您可以检查一个翻译单元程序的行为,如果需要,可以逐行执行。更复杂的程序需要离线开发环境。

标签: c++ vector sigabrt


【解决方案1】:

问题是

v_i.insert(it+k, elem);

使迭代器 it 无效,但此处再次使用该迭代器

v_i.erase(it+k);

替代代码

v_i.insert(v_i.begin()+k, elem);

v_i.erase(v_i.begin()+k);

运行时不会崩溃。并且已经提到的operator&lt;&lt; 的修复似乎给出了正确的结果。

【讨论】:

  • 谢谢,成功了!我不明白偏移如何使迭代器无效。你能指出我关于迭代器的参考吗?是时候让我再次阅读书籍了。迭代器是否因为我更新了该向量而失效?迭代器it是在更新之前为数据结构创建的,所以一旦更新了,它需要自己的迭代器吗?
  • @ccpak 不是偏移量的问题,在添加偏移量之前迭代器无效。如果将元素添加到向量,则向量的任何迭代器都可能无效。本质上,将元素添加到向量可能会导致向量重新分配其内部存储空间,如果发生这种情况,那么任何现有的迭代器仍将指向旧存储空间。
  • 再次感谢,这消除了关于迭代器失效的困惑。但是,在 gdb 中,通过观察 temp 变量,可以看出在循环的最后一次迭代中添加的 v_i 在当前迭代中变得不可访问。 v_i 的迭代器是如何计算的?因为v_i 上的擦除方法使用相同的迭代器。擦除方法不应该产生不稳定的输出,而不是 temp 上的 push_back 方法吗?
  • @ccpak 一旦你用一个无效的迭代器调用了擦除方法,你就进入了未定义行为的领域。那时一切皆有可能。使调试 C++ 变得困难的一件事是,在有问题的代码执行之后的某个时间,经常会发生崩溃或奇怪的行为。
  • 谢谢。仅通过观察调试输出很难理解这一点,因为问题仅在 temp.push_vack(v_i) 语句中很明显。你的解释清楚了。
猜你喜欢
  • 1970-01-01
  • 2023-04-03
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-23
相关资源
最近更新 更多