Why are most standard code files so confusing? And what is the type of std::vector::size?

Started by
7 comments, last by Wooh 12 years, 11 months ago
People on gamedev.net, which tbh is my main reference where coding is concerned, are always harping on, and I think rightly so, about writing code that is easy to read.

And yet today when I recieved a warning from VisualC++ telling me that there was a sign mismatch between my int type comparison with a std::vector::size call something that to me seemed contradictory to that came to my attention.

I first cast the result from the size call into an int to get rid of the warnings. Then I thought, hang on, what is the actual return type of std::vector::size?

So opened up the vector code file, and ermm, was presented with an enormous wall of WTF. Certainly not easy to read as far as I can tell. And I remembered that this is actually the case for most standard code files I've ever looked into.

Why do they almost always blatantly contradict the "easy to read" principle? Or is it just me having a very different idea of what is easy to read?

And also, what is the return type for std::vector::size? EDIT: Is it UINT, or UINT32, or unsigned int? Are they all equivalent?

Thank you.
Advertisement
It couldn't be int or unsigned it because those are different among different platforms.

It is an unsigned type for sure, though I;m not sure for its bits.

Use std::vector<yourTypeHere>::size_type and not int, because if the length of the vector exceeds INT_MAX, the size you will get will be negative.That's why there's a warning.
Your code should be easy to read and maintain because you will be working with and maintaining it. The same is not true of the standard library -- you as an end-user simply need it to work as expected, there isn't an expectation that you will want to modify or update those files. The writers of your standard library implementation have had to produce code that is safe, performs as expected, is efficient in a wide variety of potentially very different situations, and in some cases it has to be very flexible, and have had to resort to code that is less readable than might be desired in other situations in order to do so.

Rather than trying to look at the code, you might find it easier to check documentation when you have a question about the standard library, such as the MSDN page for vector::size or a reference such as this page on vector::size at cplusplus.com.


Does that help/answer your question? smile.gif

- Jason Astle-Adams

Well, I guess these functions/stuff in standard libraries are meant to be used as black boxes, and not for somebody to read/modify them.

Ahh, beaten...
The type of std::vector::size() is std::vector::size_type which will usually be the same as std::size_t (but does not have to be). In general I would advice against looking into standard header files. The place to check is the documentation (for example msdn or cplusplus.com which is the first result for googling "std::vector").

Actually, when using any kind of library, regardless of how readable it is, I would advice against looking into the code to check something out. If possible, use the library's documentation whenever at all possible. Only if that is insufficient or you suspect a bug or inconsistency would I consider looking at the code.

That said, it is well known that the C++ standard library headers are horrible to read. On the other hand, it should never really be your problem. The only line you usually have to read is the one where the assert just failed (and even that seldom because the last line in your code before entering the standard library is usually self-explanatory enough).
Edit: Memo to self: type faster.


[edit]Quadruple ninja'd! unsure.gif

Why do they almost always blatantly contradict the "easy to read" principle? Or is it just me having a very different idea of what is easy to read?
The standard library just has a very destinct ...*ahem*... style... Once you're used to that style it's somewhat easy to read.
The standard library isn't really "standard" code though - and template-meta programming tends to be ugly in general - don't look to it for inspiration.
And also, what is the return type for std::vector::size? Is it UINT, or UINT32, or unsigned int? Are they all equivalent?[/quote]It's a std::vector<T>::size_type, which if using the standard allocator is a typedef for the std::allocator<T>::size_type, which is a typedef for size_t, which is a typedef for unsigned int.
UINT and UINT32 are also usually the same as unsigned int.

It couldn't be int or unsigned it because those are different among different platforms.

It is an unsigned type for sure, though I;m not sure for its bits.

Use std::vector<yourTypeHere>::size_type and not int, because if the length of the vector exceeds INT_MAX, the size you will get will be negative.That's why there's a warning.


Rather than trying to look at the code, you might find it easier to check documentation when you have a question about the standard library, such as the MSDN page for vector::size or a reference such as this page on vector::size at cplusplus.com.


Ah thanks. I did find the size_type return value but I was confused by it, due to having been looking for an intrinsic type.


Your code should be easy to read and maintain because you will be working with and maintaining it. The same is not true of the standard library -- you as an end-user simply need it to work as expected, there isn't an expectation that you will want to modify or update those files. The writers of your standard library implementation have had to produce code that is safe, performs as expected, is efficient in a wide variety of potentially very different situations, and in some cases it has to be very flexible, and have had to resort to code that is less readable than might be desired in other situations in order to do so.


Well, I guess these functions/stuff in standard libraries are meant to be used as black boxes, and not for somebody to read/modify them.


Ah right, OK. That's interesting. Thank you.


Does that help/answer your question? smile.gif


Indeed it does. :)

EDIT:

Also thanks to the other two responses that came in before I posted this one. :P

EDIT:

]It's a std::vector<T>::size_type, which if using the standard allocator is a typedef for the std::allocator<T>::size_type, which is a typedef for size_t, which is a typedef for unsigned int.
UINT and UINT32 are also usually the same as unsigned int.


Ah I see, so it boils down to an unsigned int. Sweet. Cheers.
One problem that faces the standard library developers is that their code is in the headers that will be included into arbitrary code. You could have all sorts of #defines setup which could interact badly with a naive implementation.

So how this problem was "solved" was for the standard to set aside a set of identifiers that the "implementation" can use. These are names beginning with two underscores, and underscore and an uppercase letter, and anything in the global scope beginning with a single underscore.

So if you are writing an implementation of std::vector<>, all your identifiers are going to be decorated (read: uglified) like this.

The second issue is that there is a lot of common stuff in the standard library, and as such it makes sense to write the implementation only once. As such, it can be difficult to follow the thread of execution as you need to jump into countless helper functions/classes, each of which are not for external use and use the uglified names. You should do this in your own code too, but you get to use pretty names for the helper functions, making the calling code much easier to read.

For example, I was watching Stephan T Lavavej's latest video on the advanced STL, where he shows that std::map, std::set and std::multimap, std::multiset are implemented using a common class in Visual Studio 2010, one that uses a "traits" class to specify the differences.

Finally you are also writing the most re-used C++ code there is. There is a massive benefit to writing code that performs as fast as possible, it will speed up anything from run of the mill applications to the next big computer game. So the developers take steps to ensure that the code behaves as fast as possible in lots of special cases. A common example might be using different algorithms when there is extra information known about the types involved. For example, random access iterators often give optimisation opportunities in general algorithms, and POD types can be copied quickly using a bulk operation like memcpy().

In summary, there are lots of good reasons why the standard library maintainers have messy headers, over and above normal libraries/applications.
And also, what is the return type for std::vector::size? Is it UINT, or UINT32, or unsigned int? Are they all equivalent?
It's a std::vector<T>::size_type, which if using the standard allocator is a typedef for the std::allocator<T>::size_type, which is a typedef for size_t, which is a typedef for unsigned int.
UINT and UINT32 are also usually the same as unsigned int.
[/quote]
On 64 bit systems std::size_t is often an unsigned 64 bit integer, so it is better to use std::size_t than unsigned int.



The code itself is not standard. Each compiler use its own implementation of the standard library.

This topic is closed to new replies.

Advertisement