C++ Vectors of Objects and Pointers -
this contrived example illustrates problem i've encountered. basically, create vector of objects, vector of pointers objects, print pointers , dereferenced objects.
#include <vector> #include <iostream> using namespace std; namespace { struct myclass { int* myint; myclass(int* i) : myint(i) {} }; struct mybigclass { vector<myclass> allmyclassrecords; // keep myclass instances vector<int> theints; void loadmyclasses(); void readmyclasses(); mybigclass() {} }; } void mybigclass::loadmyclasses() { (int = 0; < 10; ++i) { theints.push_back(i); // create int int *j = &theints[theints.size() - 1]; // create pointer new int allmyclassrecords.push_back(myclass(j)); // create myclass using pointer } } void mybigclass::readmyclasses() { (vector<myclass>::iterator = allmyclassrecords.begin(); != allmyclassrecords.end(); ++it) cout << it->myint << " => " << *(it->myint) << endl; } int main() { mybigclass mbc; mbc.loadmyclasses(); mbc.readmyclasses(); }
basically, want create vector of pointers vector of ints. problem code prints out following:
0x97ea008 => 159293472 0x97ea02c => 1 0x97ea040 => 2 0x97ea044 => 3 0x97ea078 => 4 0x97ea07c => 5 0x97ea080 => 6 0x97ea084 => 7 0x97ea0d8 => 8 0x97ea0dc => 9
it appears work expected except first value, garbage in memory. why first value affected? if code broken, why broken first pointer inserted?
update: i'm compiling using g++
on ubuntu. far i'm doing, i'm creating compiler analysis pass. myclass
objects hold information instructions, want update when locate registers. register number indexes vector of vectors, particular register number have vector of myclass*s
. thus, if register found, myclass
pointers in vector used update myclass
object held in separate myclass
vector. because i'm accumulating both instruction info stored in myclass
objects , register info must follow myclass
pointers, can't create entire myclass
vector first without creating separate pass, i'd avoid.
update2: pictures...
pass progress inserts... instrecs (theint) , updates... updateptrs (myclass) ---------------------- ------------------ ----------------------- | => i1: uses r0, r1 | | instrec i1 | | r0: instrec i1* | | i2: uses r0, r2 | ------------------ | r1: instrec i1* | ---------------------- -----------------------
first pass inserts instrec info i1. creates pointers new instrec indexed register number. r0 here vector of 1 element points instrec i1, if r0 ever encountered again in subsequent instruction, instrec i1 updated.
pass progress inserts... instrecs (theint) , updates... updateptrs (myclass) ---------------------- ------------------ ----------------------- | i1: uses r0, r1 | | instrec i1 | | r0: instrec i1* | | => i2: uses r0, r2 | | instrec i2 | | instrec i2* | ---------------------- ------------------ | r1: instrec i1* | | r2: instrec i2* | -----------------------
similarly, second entry inserted instrecs , pointers added updateptrs structure. since i2 uses r0, instrec pointer pushed r0 vector. not shown this: when detected i2 uses r0, pass looks in updateptrs structure @ r0 vector of pointers, follows each pointer instrec entry, , updates instrec new info.
hopefully makes i'm trying little bit clearer. i've implemented suggestion first proposed @merickowa of using instrec vector indices rather instrec pointers (since once instrecs added array, never move), , seems working now.
its not broken on first one, happens 1 gets corrupted. if notice, pointers 0 through 7 pointing different chunks of memory when should right next each other.
std::vector can reallocate space needs dynamic objects @ time add vector , doesn't have enough capacity. can't rely on pointers (or iterators) still being valid after adding or inserting increase size.
theres many solutions like
a) can reserve space (using vector::reserve) ahead of time dynamic re-allocation doesn't occur, have know maximum number of objects you'll adding.
b) wait until objects added before getting pointers objects
c) use index object , pointer vector pair refer objects oppose object pointers directly. more work wont change (assuming you're not inserting/removing objects in beginning or middle)
d) try detect when vector has reallocated data (vector::capacity returns different value) , flush pointer vector , rebuild it
e) use different container objects doesn't reallocate on changes std::list , give random access on container of base objects, can still use vector of pointers pointers don't become invalidated. (do need random access , pointers objects?)
f) rethink design not require such pointers
Comments
Post a Comment