【问题标题】:Crash on vector pop_back() of only remaining entry仅剩余条目的向量 pop_back() 崩溃
【发布时间】:2016-10-07 07:08:53
【问题描述】:

代码:

#include <vector>
#include <algorithm>
#include <iostream>
#include <ctime>

struct myClass {
    bool bIsDead;
    myClass(bool bDead) {
        this->bIsDead = bDead;
    }
};

void PrintVector(std::vector<myClass*> vec) {
    std::cout << "The vector contains: ";
    for(int i = 0; i < vec.size(); i++) {
        std::cout << vec[i]->bIsDead << " ";
    }
    std::cout << std::endl;
}

int main() {

    std::srand(std::time(0)); // use current time as seed for rng

    std::vector<myClass*> myVector;
    for(int i = 0; i < 10; i++) {
        int tempRand = std::rand() % 2;
//      int tempRand = 1;
        if(tempRand == 1) {
            myVector.push_back(new myClass(true));
        }
        else {
            myVector.push_back(new myClass(false));
        }
    }

    std::cout << "Unsorted: " << std::endl;
    PrintVector(myVector);

    std::sort(myVector.begin(), myVector.end(), [ ]( const myClass *lhs, const myClass *rhs )
    {
        return lhs->bIsDead < rhs->bIsDead;
    });

    std::cout << "Sorted: " << std::endl;
    PrintVector(myVector);


    while(myVector.back()->bIsDead) {
        delete myVector.back();
        myVector.pop_back();
    }

    std::cout << "Removed Dead Ones: " << std::endl;
    PrintVector(myVector);

    return 0;
}

随机输入的输出:

Unsorted: 
The vector contains: 0 0 1 0 0 0 1 1 0 1 
Sorted: 
The vector contains: 0 0 0 0 0 0 1 1 1 1 
Removed Dead Ones: 
The vector contains: 0 0 0 0 0 0 

Hit ENTER to continue...

全 1 的输出(即 pop_back 删除所有):

Unsorted: 
The vector contains: 1 1 1 1 1 1 1 1 1 1 
Sorted: 
The vector contains: 1 1 1 1 1 1 1 1 1 1 

Hit ENTER to continue...

对于这个控制台应用程序,我没有收到任何错误或崩溃警告,但它没有在全 1 的情况下调用 pop_back 后输出两个 cout 语句。

关于为什么将指针向量弹出回空会导致程序崩溃的任何想法?

【问题讨论】:

  • while(myVector.back()->bIsDead) 如果myVector为空会发生什么?
  • 太长了。不管怎样,看看while(myVector.back()-&gt;bIsDead) 循环和explain it to your rubber duck
  • 哦...不是 pop_Back 导致崩溃,而是 while 循环的下一个 .back() 检查导致崩溃。我应该可以简单地添加一个 'if(empty) { break; }' 来解决这个问题。
  • 只需对delete 元素使用for 循环而不是while,然后在完成后调用myVector.clear()
  • @FriedYeti 我说你问题中的大部分信息完全没用,请相信我。

标签: c++ vector crash


【解决方案1】:

您需要添加对矢量大小的检查。如果您想使用back() 访问向量的最后一个元素,则它不应为 0。

改变这个:

while(myVector.back()->bIsDead) {

到:

while(myVector.size() > 0 && myVector.back()->bIsDead) {

这是正确的代码:

#include <vector>
#include <algorithm>
#include <iostream>
#include <ctime>

struct myClass {
    bool bIsDead;
    myClass(bool bDead) {
        this->bIsDead = bDead;
    }
};

void PrintVector(std::vector<myClass*> vec) {
    std::cout << "The vector contains: ";
    for(int i = 0; i < vec.size(); i++) {
        std::cout << vec[i]->bIsDead << " ";
    }
    std::cout << std::endl;
}

int main() {

    std::srand(std::time(0)); // use current time as seed for rng

    std::vector<myClass*> myVector;
    for(int i = 0; i < 10; i++) {
        int tempRand = std::rand() % 2;
//      int tempRand = 1;
        if(tempRand == 1) {
            myVector.push_back(new myClass(true));
        }
        else {
            myVector.push_back(new myClass(false));
        }
    }

    std::cout << "Unsorted: " << std::endl;
    PrintVector(myVector);

    std::sort(myVector.begin(), myVector.end(), [ ]( const myClass *lhs, const myClass *rhs )
    {
        return lhs->bIsDead < rhs->bIsDead;
    });

    std::cout << "Sorted: " << std::endl;
    PrintVector(myVector);


    while(myVector.size() > 0 && myVector.back()->bIsDead) {
        delete myVector.back();
        myVector.pop_back();
    }

    std::cout << "Removed Dead Ones: " << std::endl;
    PrintVector(myVector);

    return 0;
}

引用cppreference

在空容器上调用此函数(back()) 会导致未定义 行为。

PS:你不需要让这个问题看起来那么吓人来吸引我们的注意力。

【讨论】:

  • 我之前检查了(myVector.back()-&gt;bIsDead &amp;&amp; !myVector.empty()),但由于我在检查bIsDead 之前检查它是否为空,所以它仍然崩溃。
  • PS:我并没有试图让它看起来很吓人,我只是想把所有需要的信息都放进去。我花了大约 3 个小时试图找出 pop_back() 导致它崩溃的原因,并认为它更复杂,因为我在弹出后部之前确保它是空的。
  • 是的,如果是 && 运算符,则检查第一个条件,如果为真,则检查第二个条件。因此,您需要在访问元素之前检查是否为空。你有什么问题?
【解决方案2】:

与我遇到的大多数问题一样,这很简单。感谢 billz 和 juanchopanza 的 cmets,有人向我指出,崩溃的不是 pop_back(),而是在 while 循环中调用的后续 back()

这可以通过多种方式轻松解决,其中 2 个示例是: 将 if(myVector.empty) {break;} 添加到删除的 while 循环中 或者像user3286661 说的那样,在while循环中添加一个条件,首先检查它是否有一个元素。

【讨论】:

    【解决方案3】:

    问题是您尝试访问myVector.back(),即使向量已经为空。

    我能想到的侵入性最小的解决方案(对代码的最小修改)是这样的:

    while (!myVector.empty() && myVector.back()->bIsDead) {
        delete myVector.back();
        myVector.pop_back();
    }
    

    “正确”的做法是使用std::vector&lt;myClass&gt;std::vector&lt;std::unique_ptr&lt;myClass&gt;&gt;(无需手动删除)并使用erase-remove-idiom

    myVector.erase(
        std::remove_if(myVector.begin(), myVector.end(), 
            [](const auto& p) {
                return p->bIsDead; //p.bIsDead for std::vector<myClass>
            }
        ), 
        myVector.end()
    );
    

    这可能看起来更复杂,但更安全(没有意外的内存泄漏),可能更高效并且不需要调用sort

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 2012-05-17
      • 2016-06-09
      相关资源
      最近更新 更多