Learning C++

This is a series of things that I found out when learning C++. The approach is going to be non-standard and likely to annoy any normal C++ professional. I am interested in languages in general and so I will be doing all my early code without STL at all. I want to learn what features the language offers before starting to use the standard libraries. To this end I try to do do simple version of the features that are already available. That way I can see how these features are implemented in the standard libraries. To me, that feels like a important advantage in learning a language. I did try to read the code for the libraries but it has a lot of very nuanced additions that I will only get to understand much later on. The code is still interesting to step through however as it does offer clues as to how to unpick various implementations.

This page will list things that are quick to describe. Where there is a lot to say about a topic it will be its own page. For example see:

Coding Environment

I will be using Visual Studio for the editor, compiler and debugger. I did try Visual Studio Code for a while looking at Rust. However I find that while Visual Studio is bloated and has bugs etc, it is has a very low friction starting to coding and debugging, even if there is more friction later on. When I have a larger project I want to look into using 10x Editor and RemedyBG Debugger which are both awesome projects that care about usability and speed.

I will use C++ 17. See here for the reason:

Learning by stepping through the STL implementation

Visual Studio STL implementation can be found here:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC

So you can go there to read the code. It is also possible to step through the STL code. Note that Visual Studio setting default to always stepping over this code. To change this go to the menu Debug -> Settings and turn off the setting Enable Just My Code.

This can be very instructive in seeing how these things are designed. An example is that I saw that unordered_map with the std::string will take a deep copy of the chars when it is storing them in the key an values pairs. I also go to see the type of allocators that are used by default.

Be warned, as the code looks complex as it has all the support for all the compiler versions. This makes the code look very cluttered and hard to read but focusing on where the code goes can help with understanding it.

The IDE settings have grown over this process, so I have a full page dedicated to the setting from the default. See:

Speed of Learning

This methodology, does mean I have to go very slowly, trying to understand each part of an implementation. I am not that quick a coder in the first place so this is a long process. I don’t mind as I am enjoying the journey. I am using the Internet as my manual and user guide and am very happy to find the answers out there rather than just randomly trying solutions. Do this, however, has the effect that sometimes something I learn does not stick. This is also one of the motivations to doing these posts. It will allow me to capture the coding patterns rather than having to commit them to memory.

How to Annoy Stack Overflow

I have a number of interesting web sites that are helping in this journey (see below), but obviously Stack Overflow is an important resource. Interestingly, as I learn more, I find that some answers out there, while correct, may not be what you are looking for. So it is important to keep in mind your real use case when reading Stack Overflow. There is also a lot of historical answers out there and not only has the language moved on to provide better solutions but also the accepted thinking has moved on as well. So dont just take the first answers you find.

I did try asking a question and found that they seem to want code that does not work so they can show how to fix it. I put three solutions to a problem to ask which of them was the preferred idiom in C++ and was told that working code should be submitted on Stack Exchange. So I posted there as well and was told to put the code on Stack Overflow. Humm.

See this post for the full story: Asking Stack Overflow the best way to do Template Specialisation

Bit Fields

So what is wrong with the 8 byte packed structure below?

    struct meta
    {
        char            twoCC[2];
        bool            isStack : 1;
        bool            isPowerOf2 : 1;
        bool            isBlocks : 1;
        bool            isStatic : 1;
        bool            isFreed : 1;
        int             padding : 3; 
        size_t          twoByteIndex : 16;
        uint8_t         powerOf2Index;
        uint16_t        size;
    };

Times Up!

Changing type in the list will trigger an alignment.

While there is support added for bool in C++ other ‘integer types’ are not supported, and you certainly cant go over 8 bits. I liked the idea of keeping the type, so the code that used it would be OK when assigning, and having the size be smaller than its default, but that is a step to far.

 struct meta
    {
        char            twoCC[2];
        bool            isStack : 1;
        bool            isPowerOf2 : 1;
        bool            isBlocks : 1;
        bool            isStatic : 1;
        bool            isFreed : 1;
        bool            padding1 : 1; 
        bool            padding2 : 1; 
        bool            padding3 : 1; 
        uint16_t        twoBytIndex;
        uint8_t         powerOf2Index;
        uint16_t        size;
    };

Pre and Post Increment and the operator++

There is a mantra that is ‘learn to do pre-increment because it is better’. Well that is hard for those that were taught in the old days when this was not a thing. I finally heard a good explanation why… This is about performance and what is returned from the operator. All C statements return a value, even if it is not used.

int i  = 1;
i++;

The second line will evaluate to 2, but then be thrown away.

int i  = 1;
++i;

This second line will return the original value of i (the value 1) but internally do the work to increment the value of i. This would not normally be an issue as the compiler will optimise any extra work away. But! What about a class where the increment operator has to be either the pre or post increment type. For the post increment the code will have to return a new value and that could incur the cost of the ctor and copy. Where as the pre increment can return the original value/class and hence have no cost.

Hence the rule of ‘do pre increment’ as a general rule is good as you can get into the habit of it.

There is an extra part to this that needs some care too. Example taken from Visual Studio Documentation

// Prefix increment operator.
Point& Point::operator++()
{
   _x++;
   _y++;
   return *this; // Compiler can optimise
}

// Postfix increment operator.
// int is required but ignored.
Point Point::operator++(int)
{
   Point temp = *this;
   ++*this;
   return temp; // May create a copy it can't optimise
}

Links

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.