Pages

Sunday, 31 January 2021

Chapter 19 // Exercise 7 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2017 and a modified version of the std_lib_facilities header found here.

Chapter 19 // Exercise 7

Try your solution to exercise 2 with some Numbers


This one got me until I managed to find this post:

I then understood that I was trying to return a variable that was a common type between the two given template types. The compiler doesn't know that Number<int> and Number<double> are common types but Number does have ways to add themselves together and return a common type.

There is a way to define a common_type for user defined classes:

I used this to create common types for the combinations given in the exercise. It was working...in odd ways. I did some more testing and found my Number class broke spectacularly when doing Number<char> operations with any other type of number. 

It took me a while to realise it was because when assigning, it created a copy of the Number<type> with whatever type was the first operand. So for example:

When using ints and chars, it always produces 970 no matter the order. So I'm guessing that the expected behaviour of int * char is always to treat the char as an int. My Number type was not doing this due to default constructing and returning the wrong type.

I eventually found a fix for this by setting the return type of the operator overload to a common type between the two of them:

It looks hideous. I could get rid of some of the ugliness with a typedef but I left it this way for "clarity". The only problem with this, is that all combinations of common types must be declared for the class.

Thursday, 28 January 2021

Chapter 19 // Exercise 6 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2017 and a modified version of the std_lib_facilities header found here.

Chapter 19 // Exercise 6

Repeat the previous exercise, but with a class Number<T> where T can be any numeric type. Try adding % to Number and see what happens when you try to use % for Number<double> and Number<int>.


During this exercise I realised that Concepts were supposed to have become a part of the standard for C++11 and C++14 but were dropped and only now are they being introduced in C++20 (they're still not here yet). Concepts would have been perfect for this exercise as it meant we could restrict Number class to only being numeric types.

I eventually ended up finding this post:

which led me to a function in <type_traits>

So you can stick a static_assert(is_arithmetic_v<T>, "that's not a numeric type") in your class. It will check at compile time if T is a numeric type and if it's not it will print out the error message in the output log instead of some horrible template error.

Very handy. Probably not as flexible as concepts however there are other useful checks you can do with functions in type_traits:

I then wanted to be able to add ints to doubles etc., like you can do with numeric types. You will get a compiler warning due to truncation but it works. As the template already restricts it to common numerical types I didn't have to bother using common_type and templated all the operator overloads to take in a different type. If it's not a numerical type it won't even compile. If you do operations on floats and ints though you get a horrible looking warning from the compiler but it runs and rounds down as expected.

As for modulo, I can't believe it's only now that I realised you can only use it for ints; it doesn't work for floating point values. You have to use fmod(). I tried to allow for it by checking if the type was floating point but the compiler doesn't really seem to care. I thought about it and even the standard double doesn't allow it so why should I?

Wednesday, 20 January 2021

Chapter 19 // Exercise 5 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2017 and a modified version of the std_lib_facilities header found here.

Chapter 19 // Exercise 5

Define a class Int having a single member of class int. Define constructors, assignment, and operators +, -, *, / for it. Test it, and improve its design as needed (e.g., define operators << and >> for convenient I/O).


I think I went a bit overboard with the operator overloading on this one. I tried searching but I couldn't find if there is a way to reduce the amount of overloading as I only want two types allowed; int and Int. I thought about using type_traits and templating the class but then that would mean Int would need a type when declared which isn't in the brief.

Wednesday, 13 January 2021

C++ - Using NatVis files with UE4 & Visual Studio + WinDbg Funtimes

Story time
Recently at work I was debugging through a dump that had crashed in the TickTaskManger. It's the part of the engine that pretty much handles all the ticks in a frame. An object had recently spawned late in the frame, causing it's tick to be added to the NewlySpawnedTickFunctions container. The problem is that this container is a custom UE4 one known as a TSet. Unreal explains what a TSet is here:
https://docs.unrealengine.com/en-US/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/TSet/index.html

It's kind of like a map but instead of a <key, value> pair, the data itself is both key and value. When debugging through it, the only data available to me in the watch window was the LevelList (an array of TickTaskLevels for every level in the world). 

A TickTaskLevel contains a few containers itself, including the NewlySpawnedTickFunctions. When ending the frame, there is an assert to make sure that this TSet is empty, however, one of the TickTaskLevels NewlySpawnedTickFunctions had 1 element. It should've been very easy to see what tick function had added itself late in the frame by just looking at the Target member variable on the TickFunction added to the container. Instead, I was left staring at pointers, padding and random characters.

My manager easily identified what the offending UObject was that was trying to spawn and I was sat there staring at my garbage results like "but how??". Turns out that Visual Studio just had no idea how to display the information in a TSet properly and was doing it the best way it knew how. 

Enter NatVis. I had never heard of this before, there's a great post on it here:

Basically, you create a small XML file that tells VS how to display the custom container. Epic provides an XML file with their custom containers. If you have a code version of UE4 installed you can find this file on your pc around here:
[UE4Root]/Engine/Extras/VisualStudioDebugging/UE4.natvis

You need to copy this file into Visual Studio's visualisers folder. Usually located (but not always) in
C:/Users/You/Documents/Visual Studio Version/Visualizers

Or follow some of the steps below on how to add it to your project directly.

We have a tool that automatically does this for you. It's supposed to do it every time you generate project files but some reason it didn't for me. After this, TSet immediately showed me the offending owner of the tick function (it was a particle...).

Enabling NatVis in Your Own Projects
So the above Microsoft post is really straight forward...if you have debugging tools enabled and you know how to use WinDbg. I apparently did not have debugging tools enabled on my personal PC and I've used WinDbg once at work. I went down a rabbit hole trying to figure out how to follow the "straight forward" post. I eventually figured out what to do from this post:

First go to Apps & Features:

I had a few dev kits installed so I chose the newest one. Click on it and press Modify.


Choose change and then press next.


Tick the Debugging Tools For Windows box and hit change. It will then go and install it.

A Visualizers folder will have now appeared. Mine was located around here:
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\Visualizers

Now, for me Visual Studio had no problem displaying this type without help but this is some good practice with using WinDbg; the Windows 95 looking memory tracker.

I'm following this tutorial here:

In WinDbg
Open up WinDbg, then File->Open Executable and search for the .exe created when compiling the dog example program from the first link in this post.

In the command line enter:
.symfix
.symfix + (the location of the debug folder of your application)

UE4 C++ - Using Visual Studio's NatVis with UE4 (and your own projects) + WinDbg Funtimes
It will show *BUSY* for a few moments in the bottom left and then symbols will have been loaded for your program.

Next type in:
.reload
bu AppName!main        // you may get a warning after this one about verifying checksum, ignore it
g

WinDbg will now breakpoint into the program at main:
UE4 C++ - Using Visual Studio's NatVis with UE4 (and your own projects) + WinDbg Funtimes

Hit Step Into at the top (or press F11)
UE4 C++ - Using Visual Studio's NatVis with UE4 (and your own projects) + WinDbg Funtimes

Step until MyDog has been initialised. Now, even though I had added the natvis file to the visualizations folder it still didn't understand what to do. Eventually I found a command to make it load a specific natvis file from anywhere:
.nvload {filelocation}
UE4 C++ - Using Visual Studio's NatVis with UE4 (and your own projects) + WinDbg Funtimes

If you type in ??MyDog and hit enter it will show you the contents. It's readable but it could be better. Type the following
dx -r1 MyDog

and WinDbg will show the contents in our nice new readable way!

UE4 C++ - Using Visual Studio's NatVis with UE4 (and your own projects) + WinDbg Funtimes

That's great but WinDbg is kind of a pain and only useful for heavyweight developing. There is a way to add natvis files to Visual Studio.

In Visual Studio
Right click on the project in Solution Explorer and go to add new-> new item.
UE4 C++ - Using Visual Studio's NatVis with UE4 (and your own projects) + WinDbg Funtimes

Go to Visual C++->Utility and choose Debugger visualization file (.natvis)
UE4 C++ - Using Visual Studio's NatVis with UE4 (and your own projects) + WinDbg Funtimes

This will create a basic natvis file for you to add code to. When you run the program and breakpoint; there will be no difference when using the MyDog example but Microsoft gives some pretty good examples of when custom natvis files are useful here:
https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/debugger/create-custom-views-of-native-objects?view=vs-2015&redirectedfrom=MSDN

It also builds the natvis file into the pdb (symbols) of the project so if you do use WinDbg you don't have to mess around doing the above steps (but now you know how :) ).

Tuesday, 12 January 2021

Chapter 19 // Exercise 4 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2017 and a modified version of the std_lib_facilities header found here.

Chapter 19 // Exercise 4

Modify class Link from section 19.9.3 to be a template with the type of value as the template argument. Then redo exercise 13 from Chapter 17 with Link<God>.


I considered removing things that didn't make sense; like addOrdered() as Link can now be any type, how do we determine what a logical order is for any given type? Especially custom ones but then I remembered operator overloading. If we had Link<int>, addOrdered() would add it in numerical order as the check is is link1 less than link2. A string would be added in alphabetical order etc, so I added a helper to God that allows for a less than check against two Gods, returning the one whose name comes before the other. I also added another one to check if Gods were equal. 

The find() function is a bit messy as you have to pass in a God but it keeps it nice and generic for lots of other types.

The main takeaway from this exercise though was learning that templated class member functions must be implemented in the header file; if you put them in the cpp it will fail when linking. (Or they must be implemented in the same file the class is declared).

Sunday, 10 January 2021

Chapter 19 // Exercise 3 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2017 and a modified version of the std_lib_facilities header found here.

Chapter 19 // Exercise 3

Write a template class Pair that can hold a pair of values of any type. Use this to implement a simple symbol table like the one we used in the calculator (section 7.8).


.

Thursday, 7 January 2021

Chapter 19 // Exercise 2 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2017 and a modified version of the std_lib_facilities header found here.

Chapter 19 // Exercise 2

Write a template function that takes a vector<T> vt  and a vector<U> vu as arguments and returns the sum of all vt[i]*vu[i]s.


This one confused me for a bit as I pondered the best way to compare types. I had previously found a predicate called is_same that checks if to templated types are the same. It's defined in the <type_traits> header. There is a plethora of good stuff in there, along with common_type. This predicate takes in two templated types and if they are similar enough (think ints and floats) then common_type will deal with operations for you.

This also works as a concept. In section 19.3.3 I got very confused as Concepts have only just been introduced in C++20 so the concepts he's referring to here must mean something else now. I think of them as template predicates. Useful but horrible to look at.

Wednesday, 6 January 2021

Chapter 19 // Exercise 1 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2017 and a modified version of the std_lib_facilities header found here.

Chapter 19 // Exercise 1

Write a template function f() that adds the elements of one vector<T> to elements of another; for example, f(v1, v2) should do v1[i] += v2[i] for each element of v1.


My brain momentarily stopped working when I first read this exercise as I wondered how you check to see if a string is being added to a double. Or how you would define char + float? Or string + size_t? Then I remembered that a templated function with only one template argument can only be of 1 type...brains.