Saturday, 29 May 2021

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

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

Chapter 20 // Exercise 5

Define an input and output operator (<< and >>) for vector.


At first I was confused as to whether he meant std::vector or the vector we created. I decided to go with std::vector. We basically did this in Drill 14 of Chapter 19 by reading in { val, val, val } into vectors.

That seems like an odd way to type data in. So I decided on an input loop that just asks for data until you enter ctrl+z to break the loop. The main problem with this is that I have no idea how to allow reading a string with whitespace but also reading in other types. It kind of seems impossible but I'm not experienced enough to say for sure. At this point, I just ignored whitespace to bypass this problem but input and output operators for any type is begging for trouble.

EDIT 01/06/2021
After some thinking (and some googling) I realised that there is no graceful way to make a stringstream convert to any type. I was thinking of checking if T was of type std::string but comments rightfully said you should be specialising your functions more and knowing the kind of types it will be using. I eventually used this suggestion and created 2 input overloads; one for integers/characters and another for strings.

I also spent the evening adding google test to my project so I could add some automated unit tests to my project and not have to faff about with input on a console window when testing. You can read about it here:

Friday, 28 May 2021

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

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

Chapter 20 // Exercise 4

Find and fix the errors in the Jack-and-Jill example from section 20.3.1 by using STL techniques throughout.


I didn't see anything completely serious. High() can return a pointer to garbage if the containers passed in are empty. To combat this getFromJack() and getFromJill() check to see if the file is empty. If it, it returns a nullptr. That way we're not doing any unnecessary memory allocations and we can gracefully handle checks for nullptrs without crashing the program with errors. Having a nullptr is perfectly fine so I didn't want to error if the file was empty. 

I also modified getFromJill() to be able to handle any size to prevent unwanted allocations. getFromJack() is a bit more difficult as array size must be specified at compile time. A way to get round that is to read jack's data into a vector first then create the array from that size but that kind of defeats the point of using an array. I'm going to leave it the way it is for getFromJack() as arrays should be used when you know the size.

EDIT 14/06/2021
I showed this exercise to one of our senior engine programmers who pointed out that there is no handling for if the pointers supplied to high() are the correct way round. He said this could cause a near infinite loop. To be honest it never occurred to me to pass in the pointers the wrong way round, why would someone do that? I guess that's why I'm not a QA tester.

Tuesday, 25 May 2021

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

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

Chapter 20 // Exercise 3

Look at the palindrome examples (section 18.7); redo the Jack-and-Jill example from section 20.1.2 using that variety of techniques.


The wording of this confused me as those palindrome examples are about palindromes; i.e., words that are the same backwards and forwards; what has that got to do with reading in doubles?

But I stared at section 18.7.1 and realised at the heart it's just comparing two things which is what high is doing. So I re-did high to compare using the techniques from the string, array and pointer examples.

The "string" one was a bit tricky to adapt as there's really no point in going backwards unless I'm comparing two, then comparing again against the current high.

The array one was simple enough and I could use indexing which is always nice. Also, you don't need to change Jill's data into an array as a vector is basically an array; you just give it the address of the first element and the size.

I didn't do the pointer one because I had already done that in exercise 2.

Wednesday, 28 April 2021

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

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

Chapter 20 // Exercise 2

Get the Jack-and-Jill example from section 20.1.2 to work. Use input from a couple of small files to test it.


.

Wednesday, 7 April 2021

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

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

Chapter 20 // Exercise 1

If you haven't already, do all the Try this exercises in the chapter.


pg714
The one on p714 is subjective but personally I would just change 
vector<double>* jill_data 
to 
vector<double>& jill_data
incidentally, this is exactly what he does in the next section.

pg715
Here, double* high is a local variable and it is returning a pointer to a local variable. This will cause a dangling pointer as you can't return pointers to locals.  I am so dumb. After spending an evening battling with heap corruption because I thought this function was leaking memory I realised it's returning a pointer to something we already have on the stack and does not need to be newed up. GAH. I have a feeling he wanted us to discover that...

Also, the function only works with doubles and relies on values being contiguous in memory. Therefore containers like array and vector must be used. A list wouldn't work as the pointers can be anywhere in memory.

A little annoying as I couldn't use any subscripting.

pg724
The only thing I can think of is that high() is a returning a copy of the iterators into pointers? But it's creating a value on the stack due to it being a copy....I honestly don't know for this one. It ran fine when I recreated it.

push_front on a vector would be very expensive as it then needs to modify the position of everything else in the vector; what if you have a vector of 1000+ items? That's a lot of wasted cycles. A vector does have insert() which allows you to put an element anywhere in the vector and it will re-organise everything after the insertion, so you could use it to "push something to the front" if you wanted.

For the implementation, I'm lazy and rather than go get the vector I created in previous exercises I simply added push_front to the actual std::vector via Bjarne's std_lib_facilities header file and used insert().

This felt too easy....

This one is a bit confusing as I'm not sure if meant to use 1 function to compare all 4 or a separate one for each. Also, should we have passed it in as a string? Eventually I decided on 2 separate functions due to char* not being as flexible as the others.

This one was so annoying.