A quick reminder based on my experience. Recently I stumbled upon this great snippet, which lets me send graphics card a vector of data:
It is a useful one, but at first I started getting problems when calling OpenGL drawArrays*
methods.
It took me a while to realize the problem appears because of the way I filled the vector with data. Of course real code was quite complicated, but it boils down to:
- Allocate vector
- Reserve memory using precalculatedSize
- Get iterator: std::vector::begin
- Loop with unsigned int i = 0..precalculatedSize-1, set data[i]
Looks fine so far. (OK, maybe using iterator and iteration variable is a bad idea, but that’s the free-time code, right? 🙂 ).
$ clang++ -std=c++11 a.cpp; ./a.exe expectedSize = 100 data.size() = 0 data.capacity() = 100 data[2891] = 32768
…And the problem is direct memory access. Vector is told to reserve memory, but not to resize itself (compare std::vector::reserve
vs std::vector::resize
). In my case OpenGL got a buffer of size 0 and crashed.
The solution is quite simple: either to resize vector and use array access braces or reserve memory and push_back
data.
Surprisingly, iterator incrementation worked fine in this example, also for “indexes” outside vector. I also made a simple test and in my implementation (clang++ 3.9 x86_64-w64-windows-gnu
). Vector as above after reserving 100 fields returned (random) number for first 2892 fields.
Would you spot it at first sight? 😉
Not to toot my own horn, but the error seemed obvious to me, to be honest (in fact, it was jarring to read `*it = t; it++` after `reserve`).
That being said, the distinction between reserve/resize is good to know about and I can see how the presented code may be confusing for one less familiar with the language. So, good job.
By the way, a few suggestions:
– I prefer `v.data()` to `&v[0]`, though the semantics are nearly the same
– you could use `reserve` + `back_inserter` + `generate_n` or `resize` + `generate` to avoid this whole mess 😉
Thanks for suggestions. I consider myself quite a C++ beginner and code of this kind wasn’t so easy to scan through, especially when it swims in gl* spaghetti code 🙂
That being said, it would be great if you could take a while to look at final implementation and share your thoughts: https://github.com/kantoniak/konstruisto/commit/cf93a4d924e968e837e9fc38554b4ab94a489767
It’s a little too much for now, but I’ll be sure to check it out in the future 🙂
The problem boils down to a difference between “reserve” and “resize”. I think that now you won’t make this mistake again 🙂 Good that you wrote about it. Also, I second sugestions by KrzaQ.