【问题标题】:Why "vector.erase()" (in C++) is not behaving as expected?为什么 \"vector.erase()\"(在 C++ 中)没有按预期运行?
【发布时间】:2022-11-17 21:34:44
【问题描述】:

我写了一个简单的程序来测试“vector.erase”功能。有一个简单的类 (MyClass0),它在其构造函数中写入一些相关消息,在其析构函数中写入另一个消息。然后是一个向量,其中包含 4 个 MyClass0 类型的对象。当我擦除向量的第二个元素时:

    vec0.erase(vec0.begin() + 1);

我想应该在屏幕上输出消息“GoodBye From 2”。但是显示消息“GoodBye From 4”。似乎调用了向量的第 4 个元素的析构函数。 (尽管并非如此,因为当“main”完成时,第 4 个元素将在最后被破坏)。 任何人都可以帮助我,以便我找出原因。屏幕上显示的代码和输出是:

代码:

#include <iostream>
#include <vector>

using std::cout;
using std::endl;

class MyClass0
{
public:
    MyClass0(int i_i_) : i_(i_i_)
    {
        cout << "Hello From " << this->i_ << endl;
    }
    ~MyClass0()
    {
        cout << "GoodBye From " << this->i_ << endl;
    }
    std::string MyToString()
    {
        return std::string("This is ") + std::to_string(this->i_);
    }
private:
    int i_;
};


int main()
{
    std::vector<MyClass0> vec0 = { MyClass0(1), MyClass0(2), MyClass0(3), MyClass0(4) };
    cout << endl << "Before erasing..." << endl;
    vec0.erase(vec0.begin() + 1);
    cout << "After erase" << endl << endl;

    return 0;
}

屏幕输出:

Hello From 1
Hello From 2
Hello From 3
Hello From 4
GoodBye From 4
GoodBye From 3
GoodBye From 2
GoodBye From 1

Before erasing...
GoodBye From 4
After erase

GoodBye From 1
GoodBye From 3
GoodBye From 4

https://godbolt.org/z/qvrcb81Ma

【问题讨论】:

  • 也许添加复制构造函数和赋值运算符,并让它们也输出一些友好的消息。

标签: c++ vector constructor destructor erase


【解决方案1】:

矢量不允许在中间有任何孔。这意味着当您删除第二个元素时,您实际上并没有删除它。发生的情况是所有元素都向前移动以填充孔,之后向量中的最后一个元素可以被删除,因为它已经向前移动了一次

//start with
1 2 3 4

// erase 2, so move 3 into 2 and 4 into 3
1 3 4 *

// * is old 4 and we don't need that so remove it from the collection
1 3 4

// removing * calls the destructor for that element

【讨论】:

    【解决方案2】:

    考虑向量中的元素会发生什么:

    1 2 3 4
    

    这一步实际上没有擦除任何东西,我只用x标记要擦除的元素:

    1 x 3 4
    

    现在我们开始将元素复制到前面,因为剩余的元素应该是连续的:

    1 3 4 4
    

    现在缩小尺寸:

    1 3 4
    

    要删除的元素是4

    您应该实现赋值、复制和移动构造函数,以更好地了解正在发生的细节。通过operator= 将元素洗牌到前面。

    【讨论】:

      【解决方案3】:

      她是你的代码修改了一下

      class MyClass0
      {
      public:
          MyClass0(int i_i_) : i_(i_i_)
          {
              cout << "Hello From " << this->i_ << endl;
          }
          ~MyClass0()
          {
              cout << "GoodBye From " << this->i_ << endl;
          }
          std::string MyToString()
          {
              return std::string("This is ") + std::to_string(this->i_);
          }
          MyClass0(const MyClass0& other) : i_{other.i_}
          {
              std::cout << "Copy construct " << i_ << '
      ';
          }
      
          MyClass0& operator=(const MyClass0& other)
          {
              std::cout << "Asign " << other.i_ << " onto " << i_ << '
      ';
              i_ = other.i_;
              return *this;
          }
      private:
          int i_;
      };
      

      什么暴露了实际发生的事情: https://godbolt.org/z/hW177M7o6

      当 vector 从中间删除项目时,它使用 operator= 将项目分配到左侧,然后删除最后一个项目。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-01
        • 1970-01-01
        相关资源
        最近更新 更多