Memory overruns with std::vector?

Started by
4 comments, last by Will F 17 years, 1 month ago
At least, that's all I can think of. I am working on some economics code, and I have a class which needs to keep track of several possible sources for each of several possible resources. It therefore contains this:
std::vector<std::vector<Deal*> > myDeals;
(...)
myDeals.reserve(Resource::numResources);
where Deal is a helper struct containing the seller, the price, and the amount on offer. Now, at one point my buyer class goes through a list of all possible sellers, storing those that it has access to and can afford to buy from at the current price. It also registers that deal with the seller. So, now I come to testing this code. I have two buyers, which are referred to as 'ProvinceA' and 'ProvinceB'. They want to buy labour, for which there are two sellers, 'PopA' and 'PopB'. ProvinceA goes first, and registers first with PopA, increasing the size() of PopA's myDeals[labourIndex] to 1. That's just as it should be. Then it tries to register with PopB, and Something Weird happens. Here is the code for registering with a seller:

void Actor::registerBid (unsigned int res, Deal* d) {
  assert(d);
  log(stringify(this) + " Line a of registerBid; tester size " + stringify(tester-&gt;myDeals[res].size()));
  myDeals[res].push_back(d);
  log(stringify(this) + " Line b of registerBid; tester size " + stringify(tester-&gt;myDeals[res].size()));
}

Some debugging included, as you'll note. Here 'tester' is a global pointer to PopA. Now here is the output: PopB Line a of registerBid; tester size 1 PopB Line b of registerBid; tester size 4294966313 So, the code arrives in registerBid and finds that PopA has one deal registered, just as it should be. It pushes the new Deal onto PopB's vector - and suddenly calling PopA's vector's size() method gives nonsensical results. It seems to me that this is a symptom of a buffer overrun or something similar - at any rate it seems clear that PopA->myDeals[res] has got clobbered - but I don't understand how that can happen with this code. Is there some pitfall involved with using vectors of vectors? Not sure if it's relevant, but I'm using gcc 3.2.3 on Linux24SL3.
To win one hundred victories in one hundred battles is not the acme of skill. To subdue the enemy without fighting is the acme of skill.
Advertisement
reserve() is not resize().
Before examining your code further, let me ask this:
myDeals[res].push_back(d);
Are you sure that res < myDeals.size()? If not, you might consider using at() instead of operator[](), as it will throw an exception (IIRC) if the index is out of range.

My thought here (which might be totally off base), is that where you have:
myDeals.reserve(Resource::numResources);
You actually mean:
myDeals.resize(Resource::numResources);
resize() and reserve() are often confused with one another, but they do fundamentally different things.

[So very slow...]
Log/assert:
myDeals.size()
and
myDeals.size() > res

researve builds space of non-initialized data.

resize both reserves and initializes the data.

You reserve if and only if you don't want to initialize the data now, and can get around to doing it later, and you know how much data you will have, and you would rather spend the time reallocating once now then doing it "on the fly" later.
Ahhhh... *Lights up with comprehension*

Thank you, gentlemen, that solved my problem. Now it runs beautifully. Ratings all around. :)
To win one hundred victories in one hundred battles is not the acme of skill. To subdue the enemy without fighting is the acme of skill.
You might want to also take a look at this Guru of the Week article: Uses and Abuses of Vector. There are a lot of very subtle things in C++ that can cause you problems if you aren't aware of them.

This topic is closed to new replies.

Advertisement