简体   繁体   中英

Will this std::cout eventually print garbage or something unexpected?

Take a look at this code.

class Obj{
public:
    int id;
    Obj(int id) : id(id){}
};

int main()
{

    std::vector<Obj> v;

    for(int i=0; i<3; i++) // add some elements
        v.push_back(Obj(i));

    Obj& ref = v[2]; // grab references (two ways)
    Obj* ref_bad = &v[2];

    for(int i=3; i<100000; i++) // make the vector re-allocate
        v.push_back(Obj(i));

    std::cout << ref.id << std::endl; // prints 2

    std::cout << (*ref_bad).id << std::endl; // prints 2, but always?

    return 0;
}

This simple code prints 2 in both cases, but I'm not sure if this would be the behaviour for every possible execution.

Since the vector is at one point reallocating (well, not necessarily always, that depends on the segment management decisions by the OS), shouldn't this print fail at one point?

I printed the pointers using printf and %p at different points and the values were different, but I don't fully understand the behaviour of C++'s true references; is it always safe to do this? (make a C++ reference to something that might change it's memory position)

Your program has undefined behavior.

ref and ref_bad are invalidated when push_back() is called on v .

From http://en.cppreference.com/w/cpp/container/vector/push_back :

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.

Despite what somebody may say, references are actually syntactic sugar for pointers in disguise, there's exactly zero magic about them 1 .

Knowing this, it's clear that, if you keep a pointer (=reference) to memory that gets reallocated, such a pointer (=reference) becomes invalid, as it points to memory you no longer own, thus accessing it is Undefined Behavior.

Notice that, for STL containers, this is all documented - if you look up std::vector<T>::push_back you'll find that, if the new size becomes greater than the current capacity, it can invalidate all iterators and references.

That's the reason why generally when you manipulate vectors you keep indexes, not iterators or pointers.


  1. The only magic of references that I can think of is that const references can bind to tenporaries and keep them alive beyond the end of the original expression (subjected to some rules).

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