ICS 46 Spring 2022
Exercise Set 1

Due date and time: Monday, April 11, 11:59pm


Getting started

First of all, be sure that you've read the Reinforcement Exercises page, which explains everything you'll need to know, generally, about how the reinforcement exercises will work this quarter. Make sure you read that page before you continue with this one.

Before you begin work on these reinforcement exercises, there's a chore that you'll need to complete on your ICS 46 VM to get it set up to proceed.

Refreshing your ICS 46 VM environment

Even if you previously downloaded your ICS 46 VM, you will probably need to refresh its environment before proceeding with these exercises. Log into your VM and issue the command ics46 version to see what version of the ICS 46 environment you currently have stored on your VM. Note, in particular, the timestamp; if you see a version with a timestamp older than the one listed below, you'll need to refresh your environment by running the command ics46 refresh to download the latest one before you proceed with these exercises.

2022-04-05 12:09:03
Project 1 and Exercise Set 1 templates added

If you're unable to get outgoing network access to work on the ICS 46 VM — something that afflicts a handful of students each quarter — then the ics46 refresh command won't work, but an alternative approach is to download the latest environment from the link below, then to upload the file on to your ICS 46 VM using SCP. (See the Project #0 write-up for more details on using SCP.) Once the file is on your VM, you can run the command ics46 refresh_local NAME_OF_ENVIRONMENT_FILE, replacing NAME_OF_ENVIRONMENT_FILE with the name of the file you uploaded; note that you'd need to be in the same directory where the file is when you run the command.

Creating your project directory on your ICS 46 VM

A project template has been created specifically for this set of exercises, containing a similar structure to the basic template you saw in Project #0. Among other things, it contains a version of the gather script that's different from the ones in the projects, so you'll absolutely need to use the set1 template for these exercises, as opposed to the basic one.

Decide on a name for your project directory, then issue the command ics46 start YOUR_CHOSEN_PROJECT_NAME set1 to create your new project directory using the set1 template. (For example, if you wanted to call your project directory set1, you would issue the command ics46 start set1 set1.)


Problem 1 (1 point)

In Project #0, you implemented a class called String. As we discussed in our conversation about Contracts and Exceptions, when we design classes, there's more to the story than just writing code; we're designing a tool that's intended to be used elsewhere, so it's important that we carefully consider the way that tool will interact with the code that uses it. For that purpose, we consider the contracts associated with it.

Let's think about how our conversation about contracts applies to your work in Project #0, by answering a couple of questions about it.

What to submit

Add one PDF file to your core directory with this name: problem1.pdf, which contains your answers to the questions above.


Problem 2 (2 points)

We've discussed why it's so often the case that we write C++ templates in header files rather than source files. Let's explore a couple of aspects of that tendency, by answering two questions about it.

Declaring function templates separately from writing their bodies

Suppose you've decided to write a function template that you expect to use in many different source files. Suppose, further, that you haven't followed the basic advice of writing C++ templates in header files, but have instead done the following:

Now suppose that you've written a separate source file, y.cpp, in which you've written #include "x.hpp" near the top and then instantiated the function template by calling it, and that your call to the function template is a legal instantiation (i.e., it has the right number of template parameters, if specified, and they're compatible with any constraints introduced within the template).

Will it always be the case that this program can be built?

Compilation times

Suppose you've written a large C++ program that makes heavy use of templates, and that those templates are all written in header files. What effect would you expect this tendency to have on how long it takes to compile this large program, relative to an equivalent program that made no use of templates? Why?

What to submit

Add one PDF file to your core directory with this name: problem2.pdf, which contains your answer and explanation for the two questions posed above.


Problem 3 (3 points)

Write a C++ function with the following signature:

std::vector<unsigned int> countRandomFrequencies(
    unsigned int count,
    const std::vector<unsigned int>& weights)

Broadly, the function's job is to choose a bunch of random numbers and count how many times each number is chosen.

Specifically, the meanings of the function's parameters are as follows:

For example, imagine we call the function this way:

std::vector<unsigned int> weights{1, 2, 1, 2, 1, 2};
std::vector<unsigned int> frequencies = countRandomFrequencies(99, weights);

Let's examine what this would mean:

The return value, then, would be a vector whose size is the same as weights, containing the number of times each number (0, 1, 2, 3, 4, or 5) was chosen. Of course, since we're choosing 99 random numbers in this example, we would expect the sum of the values in the resulting vector to be 99.

One possible answer that we might expect would be this (because, based on the weights, we expect 1, 3, and 5 to each be chosen twice as often as 0, 2, or 4):

{ 11, 22, 11, 22, 11, 22 }

Though, of course, since you're choosing the numbers randomly, you'd naturally see some variance, though the larger the value of count, the more you'd reasonably expect the result to converge toward what it should be, based on the probabilities in weights.

What you can use

The C++ Standard Library is certainly in play here; your best bet is to pay attention to the techniques demonstrated in the Randomness notes, as well as other things declared in the <random> header, which are described in a lot more detail here.

What to submit

Add one C++ source file to your core directory with this name: problem3.cpp, which contains the definition of your function.

(You might also want to declare this function separately in a header file named problem3.hpp, so you can test it by calling it from source files in either the app or gtest directories. However, problem3.hpp is not required and will not be gathered or submitted.)


Problem 4 (2 points)

In the Smart Pointers notes, you'll find two versions of a function called downloadFile. The first one makes no attempt to handle exceptions, which means the inability to acquire the lock, connect to the network, or open the file can potentially lead to a similar failure to call close() and delete these objects subsequently, leading to resource and memory leaks. The second one fixes that problem by using the "catch-and-rethrow" technique to ensure that anything that was successfully opened is closed, even in the case of failure. Let's focus our attention only on the second of these examples.

Now let's assume that we've made the following changes in the design of the code used by that second version of the downloadFile function.

First, rewrite the downloadFile function based on these new assumptions, but make sure that it is still true that a failure to acquire the lock, establish a network connection, or open the file will not lead to memory or resource leaks (i.e., any dynamically-allocated memory will have been deleted, any resources such as locks, connections, or files will have been closed).

Next, explain in a short paragraph whether this new version of downloadFile is simpler than the second version from the notes that you've rewritten. If it was simpler, explain specifically why the RAII technique was instrumental in the improvement. If it wasn't simpler, explain specifically what's missing from the RAII technique that prevented your new function from being an improvement.

What to submit

Add one PDF file to your core directory with this name: problem4.pdf, which contains both your newly-written downloadFile function, followed by your explanation of whether and why RAII led to an improvement.

(Even though you're writing code here, you're writing something hypothetical enough — we don't actually have Lock, Connection, and File classes to test with — that there's no reason to write this in a .cpp file, since there will be no way to compile or run it.)


Problem 5 (2 points)

We've seen that C++ stores statically-allocated multidimensional arrays in first-dimension-major order. Suppose, instead, that C++ stored them using last-dimension-major order (so, the opposite) instead. For example, suppose we had this statically-allocated array:

int a[3][2][2];

then suppose that its elements were stored contiguously in memory in exactly the following order — which, again, is different from how C++ normally does it.

If that was the rule in C++, then which of the following function declarations would we expect to be illegal? For each one that you would expect to be illegal, explain in a sentence or two why. (Note that I'm asking this question generally, so the answer is never going to be "Because the capacity of x is not the same as the capacity of a in your example.")

void func1(int x[10][3])
void func2(int x[][10][20])
void func3(int x[30][])
void func4(int x[40][][][])
void func5(int x[][10][])
void func6(int x[10][][20])

What to submit

Add one PDF file to your core directory with this name: problem5.pdf, which contains your explanation of which of the six above function signatures would be illegal and, for each, why.


Deliverables

In Canvas, you'll find a separate submission area for each problem. Submit your solution to each problem into the appropriate submission area. Be sure that you're submitting the correct file into the correct area (i.e., submitting your Problem 1 solution to the area for Problem 1, and so on). Under no circumstances will we offer credit for files submited in the incorrect area.

Submit each file as-is, without putting it into a .tar.gz file or arranging it in any other way. (There is a gather script in the set1 template, but there's no need to use it.) If we asked for a PDF, for example, all we want is a PDF; no more, no less. If you submit something other than what we asked for, we will not be offering you any credit on the submission. There are no exceptions to this rule.

Of course, you should also be aware that you're responsible for submitting precisely the version of your work that you want graded. We won't regrade an exercise simply because you submitted the wrong version accidentally, and we won't be able to offer any credit on exercises that you forgot to submit.

Can I submit after the deadline?

Unlike some of the projects in this course, the reinforcement exercises cannot be submitted after the deadline; there is no late policy for these. Each is worth only 3% of your grade, so it's not a disaster if you miss one of them along the way.

Can I work on this outside of the VM?

Yes, but be aware that you must submit the files in the appropriate format, and that any C++ code you submit must compile and run on the ICS 46 VM.