用向量成员破坏对象

时间:2014-10-21 16:15:37

标签: c++ vector free destructor

我最近在使用vector作为成员编写类时遇到了一个奇怪的错误。这个bug是由我自己引入的,但运行时结果让我感到震惊。简化示例如下所示。

基本上,错误位于构造函数中,其中h2的大小只有dimension_而不是dimension_*dimension_,这会导致h2的{​​{1}}超出范围void A::set()double A::get()。我承认有这样的错误是我的坏事。我认为应该发生的是h[2]中的h[3]void A::set()将访问一些随机内存地址或仅在矢量h2的保留范围内。但真正发生的事情是,当析构函数被调用时,会引发free()错误,其后跟着很多虚拟的Backtrace,我宁愿不在这里列出。

*** glibc detected *** ./a.out: free(): invalid next size (fast): 0x0000000001637040 ***

但如果我无法访问h[3]中的void A::set(),则不会发生这种情况。我的问题是向量和析构函数究竟发生了什么?向量的析构函数是否知道我访问了哪些元素?我认为向量只知道它的大小,并在调用析构函数时释放内存。 任何想法将不胜感激。感谢。

以下是显示运行时错误的示例代码。

#include<vector>
#include<cstddef>
#include<iostream>

class A
{
    public:
        A(size_t dimension);
        virtual ~A();
    public:
        virtual double get();
        virtual void set();
    protected:
        const size_t dimension_;
        std::vector<double> h1, h2;
};

A::A(size_t dimension):
    dimension_(dimension),
    h1(dimension_*dimension_),
    h2(dimension)
{}

A::~A()
{
}

double A::get()
{
    set();
    double result(0), temp(0);
    for(size_t i(0); i < dimension_; ++i)
    {
        temp = 0;
        for(size_t j(0); j < dimension_; ++j)
            {   
                temp += h1[j] * h2[j + i*dimension_];
            }   
        result += temp * h1[i];
    }
    return result;
}

void A::set()
{
    h1[0] = h1[1] = h1[2] = h1[3] = 0.5;
    h2[0] = h2[1] = h2[2] = h2[3] = 0.005;
}

int main()
{
    A mya(2);
    std::cout << mya.get() << "\n";
    return 0;
}

1 个答案:

答案 0 :(得分:3)

使用超出范围的参数调用向量的operator[]会导致未定义的行为(UB),因此技术上任何事情都可能发生,包括您案件中发生的事情。一旦你调用UB,所有的赌注都会被取消;你无法提前知道调用UB的代码的影响。

请注意,at()方法将执行边界检查,如果您尝试访问越界元素,则会抛出异常。如果你确实访问了一个越界元素,那么你将在那一刻得到一个异常,这使调试变得更容易。缺点是边界检查需要一些额外的时间,因此如果您进行数百万次向量访问,您可能会注意到at()operator[]慢一点。是否值得权衡取决于你。


话虽如此,可能发生的事情是你正在破坏C ++实现的堆分配器使用的一些簿记结构。堆分配器通常会分配比请求的内存更多的内存,并使用额外的空间来存储有关分配本身的数据。

当向量去释放用于保存向量中元素的分配时,分配器发现它的簿记数据已被破坏,因此你最终得到了这个断言。

相关问题