data from a std::vector reference becomes corrupt after return from function call
I have a std::vector< tr1::shared_ptr<mapObject> >
that I'm trying build from data contained in a compressed file. Here's the function I'm attempting to do that with:
using std::tr1::shared_ptr;
template<typename T>
void loadSharedPtrVector(std::vector< shared_ptr<T> >& vect, TCODZip& zip)
// the TCODZip is the compression buffer I'm loading the data from. It's
// working correctly and isn't really part of this problem.
{
vect.clear();
// load the size of the saved vector
int numT = zip.getInt();
// load the saved vector
for(int i=0; i<numT; ++i)
{
int type = zip.getInt();
shared_ptr<T> Tptr(new T);
T newT = T::loadType(type, zip);
Tptr.reset(&newT);
std::cerr << "load: " << Tptr->getPosition() << std::endl; // outputs correct values
vect.push_back(Tptr);
}
for(int i=0; i<numT; ++i)
{
// outputs the last value pushed onto vect
s开发者_如何学运维td::cerr << "loadDone: " << vect[i]->getPosition() << std::endl;
}
}
The above function is called by this bit of code here:
typedef std::tr1::shared_ptr<mapObject> featurePtr;
// 'features' is a std::vector<featurePtr>, 'zip' is a TCODZip previously declared
utility::loadSharedPtrVector<mapObject>(features, zip);
vector<featurePtr>::const_iterator fit;
for(fit=features.begin(); fit<features.end(); ++fit)
{
// outputs mostly garbage
cerr << "afterCall: " << (*fit)->getPosition() << endl;
}
When this is run, the cerr
statements give this output (each set of output has ~50 lines, so I cut out most for brevity):
load: (5,40)
load: (5,45)
load: (5,58)
(etc. all 'load' lines are correct output)
load: (87,68)
load: (11,5)
loadDone: (11,5)
loadDone: (11,5)
loadDone: (11,5)
loadDone: (11,5)
loadDone: (11,5)
loadDone: (11,5)
(etc. all 'loadDone' lines are the same)
afterCall: (11,5)
afterCall: (10,1)
afterCall: (10,1)
afterCall: (10,1)
afterCall: (10,1)
afterCall: (10,1)
afterCall: (10,1)
(etc. all 'afterCall' lines are the same except for the first)
I apparently have some misconceptions about how shared_ptrs work. I realized that I'm pushing copies of Tptr
into vect
, and that's why all of its indices are the same, although I thought that declaring a new shared_ptr in the loop would make a separate pointer from the other ones already in vect
, but I guess not.
I have no idea why the 'afterCall' set of output is different from the 'loadDone' set (except for that first value). In addition to (10,1)
it has also output (2274756,134747232)
and (134747232, 16)
, although it outputs (10,1)
more than any other.
I suspect that my problem boils down to my misuse of shared_ptr
. Can anyone tell me exactly how I'm misusing it? The tutorials I find online haven't been very helpful in this regard.
The problem is here:
T newT = T::loadType(type, zip);
Tptr.reset(&newT);
You give shared_ptr
pointer to stack memory, which is reclaimed at function return and is no longer valid. Allocate that from the heap:
shared_ptr<T> Tptr( new T( T::loadType( type, zip )));
I have spotted the same defect in your code as Nikolai did, and erased the shared_ptr which is useless:
template<typename T>
void loadSharedPtrVector(std::vector<T> & vect, TCODZip& zip)
// the TCODZip is the compression buffer I'm loading the data from. It's
// working correctly and isn't really part of this problem.
{
vect.clear();
// load the size of the saved vector
int numT = zip.getInt();
// load the saved vector
for(int i=0; i<numT; ++i)
{
int type = zip.getInt();
vect.push_back(T::loadType(type, zip));
}
for(int i=0; i<numT; ++i)
{
// outputs the last value pushed onto vect
std::cerr << "loadDone: " << vect[i].getPosition() << std::endl;
}
}
精彩评论