I'm reverting to use std::vector. An empty vector is 16 bytes compared with an empty pointer which is 4 bytes, but it can simplify the code a lot.
I give up inventing another class which still claims 12 bytes when empty. It's nonsense, and too primitive compared with the STL vector.
Example:
1. type signatures
Code:
std::vector<int> m_aPrereqOrVicinityBonuses;
const std::vector<int>* CvBuildingInfo::getPrereqOrVicinityBonuses() const
// the same as `std::vector<int> const * CvBuildingInfo::getPrereqOrVicinityBonuses() const`
{
return const_cast<std::vector<int>*>(&m_aPrereqOrVicinityBonuses);
}
Notice that the function returning the pointer to vector can no longer be constant.
Edit: seems like I can const_cast the returning pointer, and it seems ok to do so.
Edit: added const keywords as
@AIAndy suggested.
Edit: should the method and the returning pointer be not constant?
Edit: I think the returning pointer can be treated as const, because the member m_aPrereqOrVicinityBonuses doesn't change address at any moment.
2. usage
Code:
const std::vector<int>* iBonus = kBuilding.getPrereqOrVicinityBonuses(); // kBuilding is of type CvBuildingInfo&
// the same as `std::vector<int> const * iBonus`
for (std::vector<int>::const_iterator it = iBonus->begin(); it != iBonus->end(); it++)
{
if (*it != NO_BONUS) // dereferencing the iterator should return the value
{ [...] }
}
Although returning the vector pointer makes its data mutable, we can ensure this doesn't happen when we handle them.
(Now that we return the pointer to a
constant vector, we have ensured this.)
Advantage of this approach: We don't need to keep a separate function that returns the size of the vector, or any information derived from the data. We just keep one which returns the pointer to our vectorized data for them to process.
If we try to ensure immutability by returning a copy of vector data instead of the pointer, we're wasting a little memory on the copies, although the copies will be removed from the stack once a function using this data finishes.
Which approach seems better?
I think, because we do pure calculations from the data most of the time, it's rather safe and quicker to give them the pointer, to reduce the size of the stack a calculating function creates.
Edit: I learned that const_iterator is better than iterator for read-only access.
Edit: It also needs the vector to be const in order to use a const_iterator. This requires our access method to have a signature of "std::vector<int> const * ". Please read AIAndy's excellent explanation below if you're not sure about the const modifier.
Tips on using a vector:
1. Reserve the space first and then add elements. This way it won't allocate an array of size we don't know and automatically expands the space by making another array (and what's worse, copy the data to there) when the space is used up.
2.
It's better to use the iterator than .push_back() to write a vector, if you've reserved the capacity correctly. (thinking again, push_back is really ok when you don't add more than reserved.)
@alberts2, I think in your new template reader SetOptionalVector() you can add aInfos.reserve(iNumSibs); in front of the loop,
and use the iterator (much like a pointer) to write the vector. .push_back() is ok