c++ - std::vector::erase() 应该销毁被删除的元素吗? (而不是最后一个元素)

标签 c++ stdvector

背景

不久前,我遇到了一些我发现非常奇怪且看似不正确的行为,我就此向 GCC 提交了错误报告。您可以在此处查看报告和我得到的回复:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47305

(我将在这里复制大部分内容。)

当时,我不明白答案,但我不是 StackOverflow 的成员,也没有人可以问这个问题,所以我只是破解了一个变通方法并继续。但是最近,我正在重新访问这段代码,但我仍然不明白这不是错误的基本原理,所以...

我的问题

在我的 Mac(目前是 OS X,Darwin 12.2.0 x86_64)附带的 C++ stdlib 发行版中,std::vector::erase() 的实现来自 /usr/include/c++/4.2.1/vector.tcc 第 106-116 行显示在此处:

template<typename _Tp, typename _Alloc>
  typename vector<_Tp, _Alloc>::iterator
  vector<_Tp, _Alloc>::
  erase(iterator __position)
  {
    if (__position + 1 != end())
      std::copy(__position + 1, end(), __position);
    --this->_M_impl._M_finish;
    this->_M_impl.destroy(this->_M_impl._M_finish);
    return __position;
  }

请注意,destroy() 将针对 last 中的元素调用 在调用此 erase() 之前 vector ,而不是为 __position 指向的元素。我认为这是不正确的——我认为是 应该为 __position 指向的元素调用 destroy()。为了 简单的 POD 类型,这没什么大不了的,但是对于那些 析构函数有副作用(例如智能指针),它可能很关键。

下面的代码说明了这个问题:

#include <vector>
#include <iostream>

class MyClass
{
    int m_x;
public:
     MyClass(int x) : m_x(x) { }
    ~MyClass()
    {
        std::cerr << "Destroying with m_x=" << m_x << std::endl;
    }
};

int main(void)
{
    std::vector<MyClass> testvect;
    testvect.reserve(8);
    testvect.push_back(MyClass(1));
    testvect.push_back(MyClass(2));
    testvect.push_back(MyClass(3));
    testvect.push_back(MyClass(4));
    testvect.push_back(MyClass(5));

    std::cerr << "ABOUT TO DELETE #3:" << std::endl;

    testvect.erase(testvect.begin() + 2);

    std::cerr << "DONE WITH DELETE." << std::endl;

    return 0;
}

当我在我的计算机上使用 g++ 4.2.1 版(无命令行参数)编译它时 Mac,当我运行它时它会产生以下内容:

Destroying with m_x=1
Destroying with m_x=2
Destroying with m_x=3
Destroying with m_x=4
Destroying with m_x=5
ABOUT TO DELETE #3:
Destroying with m_x=5
DONE WITH DELETE.
Destroying with m_x=1
Destroying with m_x=2
Destroying with m_x=4
Destroying with m_x=5

请注意,“ABOUT TO DELETE #3”消息之后的关键行显示 析构函数实际上是为我添加的第五件事(的拷贝)调用的。 重要的是, #3 的析构函数从未被调用!!

看起来 erase() 的版本也接受一个范围(两个迭代器) 有类似的问题。

所以我的问题是,我期望我从 vector 中删除的元素的析构函数被调用是错误的吗?似乎如果你不能指望这一点,你不能安全地在 vector 中使用智能指针。或者这只是 Apple 分发的 STL vector 实现中的一个错误?我是否遗漏了一些明显的东西?

最佳答案

当您删除包含3 的元素时,必须将后面的元素移回以填充空白。然后元素 #3 被分配给 #4 拥有的东西,而 #4 被分配给 #5 拥有的东西。最后一个元素 #5 将保留它的任何值,因为它无论如何都将被删除。

vector 超出范围时,您会看到剩余的 4 个元素被销毁。

如果您要在vector 中保存智能指针,则调用赋值运算符时将正确释放资源。

关于c++ - std::vector::erase() 应该销毁被删除的元素吗? (而不是最后一个元素),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12982668/

相关文章:

c++ - 解决指针算术问题

c++ - 如何将 vector 从成员函数传递给同一类中的另一个成员函数?

c++ - 直接将 std::map 插入 std::vector

c++ - 如何检查可变参数模板中的非原始类型?

c++ - std::vector 和 std::array 初始化列表之间的区别

C++ lambda 在模板的第二次扩展中没有捕获变量?

c++ - 复合模式中的内存管理

c++ - 如何在 unique_ptr 上调用函数调用运算符?

c++ - 如何将 AERT_Allocate 与 std :vector 一起使用

c++ - 从原始内存位置 memcpy 到 vector<wchar_t>