简体   繁体   中英

Can't explain why pointers become dangling when creating a vector of vectors of pointers

Consider the following code:

#include <iostream>
#include <vector>

using namespace std;

class SomeClass {
public:
    SomeClass(int num) : val_(num) {}
    int val_;
    int val() const { return val_; }
};

// Given a vector of vector of numbers, this class will generate a vector of vector of pointers
// that point to SomeClass.
class Generator {
public:
    vector<SomeClass> objects_;
    vector<vector<SomeClass*> > Generate(const vector<vector<int> >& input) {
        vector<vector<SomeClass*> > out;
        for (const auto& vec : input) {
            out.push_back({});
            for (const int num : vec) {
                SomeClass s(num);
                objects_.push_back(s);
                out.back().push_back(&objects_.back());
            }
        }
        return out;
    }
};

int main() {
    Generator generator;
    auto output = generator.Generate({{2, 3}, {4, 5}, {6}});
    for (const auto& vec : output) {
        for (const auto* obj : vec) {
            printf("%d ",obj->val());
        }
        printf("\n");
    }
    return 0;
}

The Generate method in the Generator class will simply convert the vector of vector of int s to a vector of vector of pointers to SomeClass .

SomeClass is simply a container for a simple int value with a getter method.

I would expect the following output:

2 3
4 5
6

However, I get the following output:

junk_integer junk_integer
4 5
6

It seems the pointers in the first row become dangling pointers. What is wrong with this code?

You're storing pointers into a vector , then adding elements to the vector. Since you're not reserving enough space for all the elements you're adding, when the vector resizes it invalidates all the pointers to the old data.

You'll either have to reserve enough space before storing the pointers, store the pointers after you've stored everything in the vector you need to store, or not store pointers (maybe store an index, instead).

All operations that increase the number of elements in a std::vector , including push_back() , invalidates all iterators (including pointers) that refer to elements of the vector, if the resizing results in a change of vector capacity.

Your code is doing

objects_.push_back(s);
out.back().push_back(&objects_.back());

within a loop. Every call of objects_.push_back() invalidates iterators of objects_ , and therefore can result in out.back() containing invalid (dangling) pointers.

You are storing pointers to objects contained in generator.objects_ . Some of them become dangling pointers when you call push_back() on that.

In general, storing pointers to objects in a std::vector is a bad idea.

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