I have this struct:
struct MxMInstanceData
{
D3DXVECTOR2 mTransform;
float mSpacing;
};
Then I create a vector of MxMInstanceData:
std::vector<MxMInstanceData> instInFrustumData;
If I call instInFrustumData.clear() I get this error:
Assertion failed (vector iterators
incompatible)
Vector creation code:
instInFrustumData.reserve(mNumInstances);
Vector update code:
void Terrain::updateInstances()
{
mNumInstancesInFrustum = 0;
if(instInFrustumData.size() != 0)
instInFrustumData.clear();
mpMxMInstInFrustumB->Map(D3D10_MAP_WRITE_DISCARD, NULL, (void**) &instInFrustumData);
for(int x = 0; x < mNumInstances; x++)
{
if(mpCamera->point2DInFrustum(instData[x].mTransform +
D3DXVECTOR2(instData[x].mSpacing/2 + mpCamera->getPosition().x, instData[x].mSpacing/2 + mpCamera->getPosition().z), instData[x].mSpacing/2)
!= OUTSIDE)
{
instInFrustumData.push_back(instData[x]);
mNumInstancesInFrustum++;
}
}
mpMxMInstInFrustumB->Unmap();
}
What can make this happen?
And in the destructor of my class I also call clear()
You may want to check out a reference on using std::vector like http://www.cplusplus.com/reference/stl/vector/ or buy a good STL book. You are using some methods in what I would consider unorthodox ways.
Use empty() to check if a vector has elements (if not empty clear just reads better)
Use locally scoped variables when possible (things that don't need to stay in scope shouldn't)
Use STL iterators or container sizes in loops (is having two incrementing integers in one loop needed?)
Use the "best" STL container for your implementation (do you want vectors or maps here?)
Avoid C-style casts and misuse of objects ((void**) &instInFrustumData is a very bad idea)
You have so many members variables whose definition is unknown as well unknown methods Map() and UnMap() and still haven't shown any code using iterators related to your original error. I would guess your use of instData[x] is dangerous and problematic as well as the way that loop is constructed in general. You also really don't want to be treating STL containers as anything but STL containers. Things like (void**) &instInFrustumData should be avoided as they can only cause problems.
I highly suggest you learn C++ first before tackling DirectX or graphics and game engines written in both.
Kind of guessing here, but maybe your problem is this line:
mpMxMInstInFrustumB->Map(D3D10_MAP_WRITE_DISCARD, NULL, (void**) &instInFrustumData);
You're passing a pointer to the vector itself to this Map function, which I'm guessing might be overwriting some of its internals? I don't have its documentation, but it doesn't look like a function that's expecting a pointer to a vector :)
Related
This question is about owning pointers, consuming pointers, smart pointers, vectors, and allocators.
I am a little bit lost on my thoughts about code architecture. Furthermore, if this question has already an answer somewhere, 1. sorry, but I haven't found a satisfying answer so far and 2. please point me to it.
My problem is the following:
I have several "things" stored in a vector and several "consumers" of those "things". So, my first try was like follows:
std::vector<thing> i_am_the_owner_of_things;
thing* get_thing_for_consumer() {
// some thing-selection logic
return &i_am_the_owner_of_things[5]; // 5 is just an example
}
...
// somewhere else in the code:
class consumer {
consumer() {
m_thing = get_thing_for_consumer();
}
thing* m_thing;
};
In my application, this would be safe because the "things" outlive the "consumers" in any case. However, more "things" can be added during runtime and that can become a problem because if the std::vector<thing> i_am_the_owner_of_things; gets reallocated, all the thing* m_thing pointers become invalid.
A fix to this scenario would be to store unique pointers to "things" instead of "things" directly, i.e. like follows:
std::vector<std::unique_ptr<thing>> i_am_the_owner_of_things;
thing* get_thing_for_consumer() {
// some thing-selection logic
return i_am_the_owner_of_things[5].get(); // 5 is just an example
}
...
// somewhere else in the code:
class consumer {
consumer() {
m_thing = get_thing_for_consumer();
}
thing* m_thing;
};
The downside here is that memory coherency between "things" is lost. Can this memory coherency be re-established by using custom allocators somehow? I am thinking of something like an allocator which would always allocate memory for, e.g., 10 elements at a time and whenever required, adds more 10-elements-sized chunks of memory.
Example:
initially:
v = ☐☐☐☐☐☐☐☐☐☐
more elements:
v = ☐☐☐☐☐☐☐☐☐☐ 🡒 ☐☐☐☐☐☐☐☐☐☐
and again:
v = ☐☐☐☐☐☐☐☐☐☐ 🡒 ☐☐☐☐☐☐☐☐☐☐ 🡒 ☐☐☐☐☐☐☐☐☐☐
Using such an allocator, I wouldn't even have to use std::unique_ptrs of "things" because at std::vector's reallocation time, the memory addresses of the already existing elements would not change.
As alternative, I can only think of referencing the "thing" in "consumer" via a std::shared_ptr<thing> m_thing, as opposed to the current thing* m_thing but that seems like the worst approach to me, because a "thing" shall not own a "consumer" and with shared pointers I would create shared ownership.
So, is the allocator-approach a good one? And if so, how can it be done? Do I have to implement the allocator by myself or is there an existing one?
If you are able to treat thing as a value type, do so. It simplifies things, you don't need a smart pointer for circumventing the pointer/reference invalidation issue. The latter can be tackled differently:
If new thing instances are inserted via push_front and push_back during the program, use std::deque instead of std::vector. Then, no pointers or references to elements in this container are invalidated (iterators are invalidated, though - thanks to #odyss-jii for pointing that out). If you fear that you heavily rely on the performance benefit of the completely contiguous memory layout of std::vector: create a benchmark and profile.
If new thing instances are inserted in the middle of the container during the program, consider using std::list. No pointers/iterators/references are invalidated when inserting or removing container elements. Iteration over a std::list is much slower than a std::vector, but make sure this is an actual issue in your scenario before worrying too much about that.
There is no single right answer to this question, since it depends a lot on the exact access patterns and desired performance characteristics.
Having said that, here is my recommendation:
Continue storing the data contiguously as you are, but do not store aliasing pointers to that data. Instead, consider a safer alternative (this is a proven method) where you fetch the pointer based on an ID right before using it -- as a side-note, in a multi-threaded application you can lock attempts to resize the underlying store whilst such a weak reference lives.
So your consumer will store an ID, and will fetch a pointer to the data from the "store" on demand. This also gives you control over all "fetches", so that you can track them, implement safety measure, etc.
void consumer::foo() {
thing *t = m_thing_store.get(m_thing_id);
if (t) {
// do something with t
}
}
Or more advanced alternative to help with synchronization in multi-threaded scenario:
void consumer::foo() {
reference<thing> t = m_thing_store.get(m_thing_id);
if (!t.empty()) {
// do something with t
}
}
Where reference would be some thread-safe RAII "weak pointer".
There are multiple ways of implementing this. You can either use an open-addressing hash table and use the ID as a key; this will give you roughly O(1) access time if you balance it properly.
Another alternative (best-case O(1), worst-case O(N)) is to use a "reference" structure, with a 32-bit ID and a 32-bit index (so same size as 64-bit pointer) -- the index serves as a sort-of cache. When you fetch, you first try the index, if the element in the index has the expected ID you are done. Otherwise, you get a "cache miss" and you do a linear scan of the store to find the element based on ID, and then you store the last-known index value in your reference.
IMO best approach would be create new container which will behave is safe way.
Pros:
change will be done on separate level of abstraction
changes to old code will be minimal (just replace std::vector with new container).
it will be "clean code" way to do it
Cons:
it may look like there is a bit more work to do
Other answer proposes use of std::list which will do the job, but with larger number of allocation and slower random access. So IMO it is better to compose own container from couple of std::vectors.
So it may start look more or less like this (minimum example):
template<typename T>
class cluster_vector
{
public:
static const constexpr cluster_size = 16;
cluster_vector() {
clusters.reserve(1024);
add_cluster();
}
...
size_t size() const {
if (clusters.empty()) return 0;
return (clusters.size() - 1) * cluster_size + clusters.back().size();
}
T& operator[](size_t index) {
thowIfIndexToBig(index);
return clusters[index / cluster_size][index % cluster_size];
}
void push_back(T&& x) {
if_last_is_full_add_cluster();
clusters.back().push_back(std::forward<T>(x));
}
private:
void thowIfIndexToBig(size_t index) const {
if (index >= size()) {
throw std::out_of_range("cluster_vector out of range");
}
}
void add_cluster() {
clusters.push_back({});
clusters.back().reserve(cluster_size);
}
void if_last_is_full_add_cluster() {
if (clusters.back().size() == cluster_size) {
add_cluster();
}
}
private:
std::vector<std::vector<T>> clusters;
}
This way you will provide container which will not reallocate items. It doesn't meter what T does.
[A shared pointer] seems like the worst approach to me, because a "thing" shall not own a "consumer" and with shared pointers I would create shared ownership.
So what? Maybe the code is a little less self-documenting, but it will solve all your problems.
(And by the way you are muddling things by using the word "consumer", which in a traditional producer/consumer paradigm would take ownership.)
Also, returning a raw pointer in your current code is already entirely ambiguous as to ownership. In general, I'd say it's good practice to avoid raw pointers if you can (like you don't need to call delete.) I would return a reference if you go with unique_ptr
std::vector<std::unique_ptr<thing>> i_am_the_owner_of_things;
thing& get_thing_for_consumer() {
// some thing-selection logic
return *i_am_the_owner_of_things[5]; // 5 is just an example
}
If I have this function:
void initPoints(sf::Vector2f points[]);
Why can I do this:
sf::Vector2f[] vecs = {sf::Vector2f(0,0), etc};
initPoints(vecs);
But can't do this?
initPoints({sf::Vector2f(0,0), etc});
VS gives me an error on the second one, but not on the first one.
By using std::vector or std::array you can resolve your problem easier :)
Furthermore, std::vector is RAII-conform, so you don't have to manage the memory by yourself. Generally, STL classes are better than C-type arrays.
#include <vector>
#include <initializer_list>
// ...
std::vector<sf::Vector2f> vecs = { Vector2f(0,0), etc };
Then:
initPoints(const std::vector<sf::Vector2f>& vec) {
// ...
}
initPoints(vecs);
C++ generally doesn't allow you to pass an actual array as a function parameter. It has a convenience feature that makes you think that's possible, in that you can actually pass a pointer.
In other words:
void initPoints(sf::Vector2f points[]);
Is the same thing as
void initPoints(sf::Vector2f* points);
Note that initPoints doesn't know the length of points, so generally you also pass a length parameter:
void initPoints(sf:Vector2f* points, size_t length);
What you're trying to do simply isn't valid pre-C++11. In C++11 you can overload initPoints() to take a std::initializer_list<sf::Vector2f>, and the syntax will work fine.
The kind of array you're using is often called a "C-style array." It exists in C, and has existed in C++ from the beginning. It has various limitations, such as what you've just run into. It looks like you really want a std::vector. There is some nuance to using std::vectors, and I don't know your level of C++ understanding, so I don't know if the phrases "usually you don't want to pass them by value" or "I would recommend you imitate STL functions and pass begin/end iterators instead" mean anything to you. You will eventually come across the parts of the language that make those statements useful. You don't need to worry about them right now.
Problem:
In COM you occasionally find functions with signatures like this:
HRESULT STDMETHODCALLTYPE GetColorContexts(
UINT cCount,
IWICColorContext **ppIColorContexts,
UINT *pcActualCount)
The problem this presents for me is that ppIColorContexts must be an initialized array of IWICColorContext *. I have tried referencing the first element of a Vector of ATL::CComPtr<IWICColorContext> with no such luck it won't trigger the () operator so it complains about a type mismatch.
Attempted solutions:
vector<ATL::CComPtr<IWICColorContext>> failed due to type mismatch, as noted in the comments this has other issues as CComPtr overloads operator & which breaks STL containers. It seems that this was fixed in C++11 and was included in the STL in VC2010
BOOST_SCOPE_EXIT_ALL works but still means I'm manually managing the lifetime of the COM objects which is something I'd like to get away from.
Unattempted solutions:
Custom data structure - this is likely what I'll have to do if there is not a more elegant solution, but at least it would allow me to take advantage of destruction semantics properly.
Attach a CComPtr after this call - I dislike this solution because it leaves me with a period of execution where the resource may not get released if something goes wrong.
std::unique_ptr<IWICColorContext[]> with a custom deleter - I have yet to fully explore this possibility but it would ensure that the COM objects would always get released.
I would do it by passing a vector of raw pointers to the function, then copying to another vector of CComPtr.
std::vector<IWICColorContext *> vec(5, NULL);
UINT nActualCount = 0;
GetColorContexts(vec.size(), &vec[0], &nActualCount);
std::vector<CComPtr<IWICColorContext> > results(vec.begin(), vec.begin() + nActualCount);
The only unfortunate part is that the CComPtr constructor performs an AddRef so you must do a corresponding Release on the raw pointers before they're lost.
for (auto it = vec.begin(); it != vec.end(); ++it)
if (*it != NULL)
(*it)->Release();
vec.clear();
Ultimately the solution was described by igor tandetnik in the comments above:
Basically in VC2010+ ATL::CComPtr has a sizeof that is the same as the pointer they represent (e.g. sizeof(ATL::CComPtr<IWICColorContext>) == sizeof(IWICColorContext*)), as best I can tell this is because they have no virtual functions and thus need no vTable. This is however highly dangerous as it's relying on a compiler implementation detail. Thus the following works:
std::vector<ATL::CComPtr<IWICColorContext> > > vec(5);
// CComPtrs are created and initialized here
GetColorContexts(vec.size(), &vec[0].m_T, ...);
Mark brought up a very good point that the solution above was completely dependent on compiler implementation which is dangerous. However the solution of only attaching ATL::CComPtr after the GetColorContexts call was not palattable either as it would not have been exception safe.
Ultimately my solution (tested this morning) is to create a vector<IWICColorContext*> temporarily from the vector<CComPtr<IWICColorContext>> this temporary vector does not increment the ref count and allows me to maintain exception safety.
I think that you need something like that:
long lSize = 0;
ptr->GetColorContexts(cCount, NULL, &lSize);//return required amount of contexts
IWICColorContext** ppColorContexts = NULL;
ppColorContexts = new IWICColorContext*[lSize];
ptr->GetColorContexts(cCount, ppColorContexts, &lSize);
//use something to wrap received raw interfaces with CComPtr -
//for example use for loop to pass them to new container,
//which stores CComPtr<IWICColorContext>
Should I be worried about having too many levels of vectors in vectors?
For example, I have a hierarchy of 5 levels and I have this kind of code
all over my project:
rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d]
where each element is a vector. The whole thing is a vector of vectors of vectors ...
Using this still should be lot faster than copying the object like this:
Block b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
// use b
The second approach is much nicer, but slower I guess.
Please give me any suggestion if I should worry about performance issues related to this,
or else...
Thanks
Efficiency won't really be affected in your code (the cost of a vector random access is basically nothing), what you should be concerned with is the abuse of the vector data structure.
There's little reason that you should be using a vector over a class for something as complex as this. Classes with properly defined interfaces won't make your code any more efficient, but it WILL make maintenance much easier in future.
Your current solution can also run into undefined behaviour. Take for example the code you posted:
Block b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
Now what happens if the vector indexes referred to by pos.a, pos.b, pos.c, pos.d don't exist in one of those vectors? You'll go into undefined behaviour and your application will probably segfault (if you're lucky).
To fix that, you'll need to compare the size of ALL vectors before trying to retrieve the Block object.
e.g.
Block b;
if ((pos.a < rawSheets.size()) &&
(pos.b < rawSheets[pos.a].countries.size()) &&
(pos.c < rawSheets[pos.a].countries[pos.b].cities.size()) &&
(pos.d < rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks.size()))
{
b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
}
Are you really going to do that every time you need a block?!!
You could do that, or you can, at the very least, wrap it up in a class...
Example:
class RawSheet
{
Block & FindBlock(const Pos &pos);
std::vector<Country> m_countries;
};
Block & RawSheet::FindBlock(const Pos &pos)
{
if ((pos.b < m_countries.size()) &&
(pos.c < m_countries[pos.b].cities.size()) &&
(pos.d < m_countries[pos.b].cities[pos.c].blocks.size()))
{
return m_countries[pos.b].cities[pos.c].blocks[pos.d];
}
else
{
throw <some exception type here>;
}
}
Then you could use it like this:
try
{
Block &b = rawSheets[pos.a].FindBlock(pos);
// Do stuff with b.
}
catch (const <some exception type here>& ex)
{
std::cout << "Unable to find block in sheet " << pos.a << std::endl;
}
At the very least, you can continue to use vectors inside the RawSheet class, but with it being inside a method, you can remove the vector abuse at a later date, without having to change any code elsewhere (see: Law Of Demeter)!
Use references instead. This doesn't copy an object but just makes an alias to make it more usable, so performance is not touched.
Block& b = rawSheets[pos.a].countries[pos.b].cities[pos.c].blocks[pos.d];
(watch the ampersand). When you use b you will be working with the original vector.
But as #delnan notes you should be worried more about your code structure - I'm sure you could rewrite it in a more appropriate and maintable way.
You should be worried about specific answers since we don't know what the constraints are for your program or even what it does?
The code you've given isn't that bad given what little we know.
The first and second approaches you've shown are functionally identical. Both by default will return an object reference but depending on assignment may result in a copy being made. The second certainly will.
Sasha is right in that you probably want a reference rather than a copy of the object. Depending on how you're using it you may want to make it const.
Since you're working with vectors, each call is fixed time and should be quite fast. If you're really concerned, time the call and consider how often the call is made per second.
You should also consider the size of your dataset and think about if another data structure (database perhaps) would be more appropriate.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why use iterators instead of array indices?
I'm reviewing my knowledge on C++ and I've stumbled upon iterators. One thing I want to know is what makes them so special and I want to know why this:
using namespace std;
vector<int> myIntVector;
vector<int>::iterator myIntVectorIterator;
// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);
for(myIntVectorIterator = myIntVector.begin();
myIntVectorIterator != myIntVector.end();
myIntVectorIterator++)
{
cout<<*myIntVectorIterator<<" ";
//Should output 1 4 8
}
is better than this:
using namespace std;
vector<int> myIntVector;
// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);
for(int y=0; y<myIntVector.size(); y++)
{
cout<<myIntVector[y]<<" ";
//Should output 1 4 8
}
And yes I know that I shouldn't be using the std namespace. I just took this example off of the cprogramming website. So can you please tell me why the latter is worse? What's the big difference?
The special thing about iterators is that they provide the glue between algorithms and containers. For generic code, the recommendation would be to use a combination of STL algorithms (e.g. find, sort, remove, copy) etc. that carries out the computation that you have in mind on your data structure (vector, list, map etc.), and to supply that algorithm with iterators into your container.
Your particular example could be written as a combination of the for_each algorithm and the vector container (see option 3) below), but it's only one out of four distinct ways to iterate over a std::vector:
1) index-based iteration
for (std::size_t i = 0; i != v.size(); ++i) {
// access element as v[i]
// any code including continue, break, return
}
Advantages: familiar to anyone familiar with C-style code, can loop using different strides (e.g. i += 2).
Disadvantages: only for sequential random access containers (vector, array, deque), doesn't work for list, forward_list or the associative containers. Also the loop control is a little verbose (init, check, increment). People need to be aware of the 0-based indexing in C++.
2) iterator-based iteration
for (auto it = v.begin(); it != v.end(); ++it) {
// if the current index is needed:
auto i = std::distance(v.begin(), it);
// access element as *it
// any code including continue, break, return
}
Advantages: more generic, works for all containers (even the new unordered associative containers, can also use different strides (e.g. std::advance(it, 2));
Disadvantages: need extra work to get the index of the current element (could be O(N) for list or forward_list). Again, the loop control is a little verbose (init, check, increment).
3) STL for_each algorithm + lambda
std::for_each(v.begin(), v.end(), [](T const& elem) {
// if the current index is needed:
auto i = &elem - &v[0];
// cannot continue, break or return out of the loop
});
Advantages: same as 2) plus small reduction in loop control (no check and increment), this can greatly reduce your bug rate (wrong init, check or increment, off-by-one errors).
Disadvantages: same as explicit iterator-loop plus restricted possibilities for flow control in the loop (cannot use continue, break or return) and no option for different strides (unless you use an iterator adapter that overloads operator++).
4) range-for loop
for (auto& elem: v) {
// if the current index is needed:
auto i = &elem - &v[0];
// any code including continue, break, return
}
Advantages: very compact loop control, direct access to the current element.
Disadvantages: extra statement to get the index. Cannot use different strides.
What to use?
For your particular example of iterating over std::vector: if you really need the index (e.g. access the previous or next element, printing/logging the index inside the loop etc.) or you need a stride different than 1, then I would go for the explicitly indexed-loop, otherwise I'd go for the range-for loop.
For generic algorithms on generic containers I'd go for the explicit iterator loop unless the code contained no flow control inside the loop and needed stride 1, in which case I'd go for the STL for_each + a lambda.
With a vector iterators do no offer any real advantage. The syntax is uglier, longer to type and harder to read.
Iterating over a vector using iterators is not faster and is not safer (actually if the vector is possibly resized during the iteration using iterators will put you in big troubles).
The idea of having a generic loop that works when you will change later the container type is also mostly nonsense in real cases. Unfortunately the dark side of a strictly typed language without serious typing inference (a bit better now with C++11, however) is that you need to say what is the type of everything at each step. If you change your mind later you will still need to go around and change everything. Moreover different containers have very different trade-offs and changing container type is not something that happens that often.
The only case in which iteration should be kept if possible generic is when writing template code, but that (I hope for you) is not the most frequent case.
The only problem present in your explicit index loop is that size returns an unsigned value (a design bug of C++) and comparison between signed and unsigned is dangerous and surprising, so better avoided. If you use a decent compiler with warnings enabled there should be a diagnostic on that.
Note that the solution is not to use an unsiged as the index, because arithmetic between unsigned values is also apparently illogical (it's modulo arithmetic, and x-1 may be bigger than x). You instead should cast the size to an integer before using it.
It may make some sense to use unsigned sizes and indexes (paying a LOT of attention to every expression you write) only if you're working on a 16 bit C++ implementation (16 bit was the reason for having unsigned values in sizes).
As a typical mistake that unsigned size may introduce consider:
void drawPolyline(const std::vector<P2d>& points)
{
for (int i=0; i<points.size()-1; i++)
drawLine(points[i], points[i+1]);
}
Here the bug is present because if you pass an empty points vector the value points.size()-1 will be a huge positive number, making you looping into a segfault.
A working solution could be
for (int i=1; i<points.size(); i++)
drawLine(points[i - 1], points[i]);
but I personally prefer to always remove unsinged-ness with int(v.size()).
PS: If you really don't want to think by to yourself to the implications and simply want an expert to tell you then consider that a quite a few world recognized C++ experts agree and expressed opinions on that unsigned values are a bad idea except for bit manipulations.
Discovering the ugliness of using iterators in the case of iterating up to second-last is left as an exercise for the reader.
Iterators make your code more generic.
Every standard library container provides an iterator hence if you change your container class in future the loop wont be affected.
Iterators are first choice over operator[]. C++11 provides std::begin(), std::end() functions.
As your code uses just std::vector, I can't say there is much difference in both codes, however, operator [] may not operate as you intend to. For example if you use map, operator[] will insert an element if not found.
Also, by using iterator your code becomes more portable between containers. You can switch containers from std::vector to std::list or other container freely without changing much if you use iterator such rule doesn't apply to operator[].
It always depends on what you need.
You should use operator[] when you need direct access to elements in the vector (when you need to index a specific element in the vector). There is nothing wrong in using it over iterators. However, you must decide for yourself which (operator[] or iterators) suits best your needs.
Using iterators would enable you to switch to other container types without much change in your code. In other words, using iterators would make your code more generic, and does not depend on a particular type of container.
By writing your client code in terms of iterators you abstract away the container completely.
Consider this code:
class ExpressionParser // some generic arbitrary expression parser
{
public:
template<typename It>
void parse(It begin, const It end)
{
using namespace std;
using namespace std::placeholders;
for_each(begin, end,
bind(&ExpressionParser::process_next, this, _1);
}
// process next char in a stream (defined elsewhere)
void process_next(char c);
};
client code:
ExpressionParser p;
std::string expression("SUM(A) FOR A in [1, 2, 3, 4]");
p.parse(expression.begin(), expression.end());
std::istringstream file("expression.txt");
p.parse(std::istringstream<char>(file), std::istringstream<char>());
char expr[] = "[12a^2 + 13a - 5] with a=108";
p.parse(std::begin(expr), std::end(expr));
Edit: Consider your original code example, implemented with :
using namespace std;
vector<int> myIntVector;
// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);
copy(myIntVector.begin(), myIntVector.end(),
std::ostream_iterator<int>(cout, " "));
The nice thing about iterator is that later on if you wanted to switch your vector to a another STD container. Then the forloop will still work.
its a matter of speed. using the iterator accesses the elements faster. a similar question was answered here:
What's faster, iterating an STL vector with vector::iterator or with at()?
Edit:
speed of access varies with each cpu and compiler