简体   繁体   中英

destruction of object with vector member

I recently encountered a weird bug when coding classes with vector as member. The bug is introduced by myself but the runtime result shocked me. The simplified example is shown below.

Basically the bug is in the constructor where h2 only has a size of dimension_ rather than dimension_*dimension_ , which leads to out-of-range access of h2 in void A::set() and double A::get() . I admit it's my bad to have such kind of bug. What I would think it should happen is that h[2] and h[3] in void A::set() will access some random memory address or just in the reserved range of vector h2 . But what has really happened is when destructor is called a free() error is raised, which follow by a lot of dummy Backtrace I would rather not list here.

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

But if I don't access h[3] in void A::set() , this won't happen. My question is what is really happening with the vector and the destructor? Does the vector's destructor know which elements I have accessed? I would think the vector only knows its size and deallocate the memory when destructor is called. Any idea will be appreciated. Thanks.

The following is the sample code that manifests the runtime error.

#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;
}

Calling a vector's operator[] with an out-of-range argument results in undefined behavior (UB) so technically anything at all might happen , including what is happening in your case. Once you invoke UB all bets are off; you cannot reason ahead of time about the effects of code that invokes UB.

Note that the at() method will do bounds checking and will throw an exception if you attempt to access an out-of-bounds element. If you do access an out of bounds element you will get an exception right at that moment, which makes debugging easier. The downside is that the bounds checks take a bit of extra time, and so if you are doing millions of vector accesses you may notice that at() is a bit slower than operator[] . Whether or not the trade-off is worth it is up to you.


Having said that, what is likely happening is that you are clobbering some book-keeping structures used by your C++ implementation's heap allocator. Heap allocators typically allocate a bit more memory than requested, and use the extra space to store data about the allocation itself.

When the vector goes to free the allocation used to hold the elements in the vector, the allocator finds that its book-keeping data has been destroyed, and so you wind up with this assert.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM