Spring 2006 CS 188

Homework 2

Time due: 9:00 PM Monday, June 5

This is a short homework to give you experience with C++ exceptions.

Try running the program at the end of this writeup, and notice that it occasionally fails to clean up after itself by removing the temporary file it creates.

  1. Copy the program and modify (only) the doSomething function to ensure that the temporary file is removed even if displayJpeg throws. Do this by introducing a try-catch in doSomething.

  2. The solution in problem 1 doesn't scale very well; if the program creates lots of temporary files in various functions, there would be a lot of repetitive code. Once again, copy the original program and modify the doSomething function to ensure that the temporary file is removed even if displayJpeg throws. This time, use the Resource Acquisition Is Initialization idiom: Define a TempFile class to manage the temporary file; the constructor should throw the FileException if the file can't be created. Notice how this solution scales up very nicely for programs that create a lot of temporary files.

    Once you get the basic modification done, uncomment the lines in doSomething that actually do something with the temporary file. Do what is necessary to the TempFile class and to those lines so that clients can use operator<< and can call member functions like put, write, and flush on the underlying file. Do this in such a way that you, the designer of the TempFile class, don't have to know everything that can done to an ofstream.

Turn it in

Turn in the two .cpp files at the CS 188 submission site.

Here's the Program

#include <iostream>
#include <string>
#include <fstream>    // defines std::ofstream and std::ifstream
#include <cstdio>     // defines std::remove
#include <cstdlib>    // defines std::srand and std::rand
#include <ctime>      // defines std::time
#include <stdexcept>  // defines std::runtime_error

using namespace std;

const char* TEMPFILENAME = "mytempfile";
  // To test for failure to create the temporary file in doSomething, change
  // this to, for example, "someNonexistentDirectory/mytempfile"

class FileException : public runtime_error
{
  public:
    FileException(const string& msg) : runtime_error(msg) {}
};

class InvalidJpegException : public runtime_error
{
  public:
    InvalidJpegException(const string& msg) : runtime_error(msg) {}
};

void doSomething();
void displayJpeg(const string& filename);

int main()
{
    srand(time(0));
    try
    {
        doSomething();
        cout << "doSomething succeeded." << endl;
    }
    catch (const FileException& ex)
    {
        cout << "doSomething aborted with a file error: " << ex.what() << endl;
    }
    catch (const runtime_error& ex)
    {
        cout << "doSomething aborted with some runtime error: " << ex.what() << endl;
    }
        // See if the temp file still exists.  Both UNIX and Windows have
        // better ways of doing this than by trying to open the file for
        // reading, but they aren't part of Standard C++.
    ifstream tf(TEMPFILENAME);
    if (tf)
        cout << TEMPFILENAME << " still exists, which is bad." << endl;
    else
        cout << TEMPFILENAME << " doesn't exist, which is good." << endl;
}

void doSomething()
{
      // Create a temporary file
    ofstream tempf(TEMPFILENAME);
    if (!tempf)
        throw FileException(TEMPFILENAME);

      // Do things with the temporary file
    // tempf << "Hello!" << endl;
    // tempf << 123;
    // tempf.put('=');
    // tempf.write("123", 3);
    // tempf.put('\n');
    // tempf.flush();

      // Show a pretty picture
    displayJpeg("aPrettyPicture.jpg");

      // Do more things with the temporary file
    // tempf << "Goodbye!" << endl;

      // Delete temporary file
    tempf.close();
    remove(TEMPFILENAME);
}

void displayJpeg(const string& filename)
{
      // A real implementation would open the JPEG file
      // and display it if it was properly formed, or
      // throw an InvalidJpegException if it wasn't.
      // For this assignment, we'll just simulate
      // occasional failures.

    bool isValidJpeg = (rand() % 3 != 0);
    if (!isValidJpeg)
        throw InvalidJpegException(filename);

    cout << "There's a nice picture in " << filename << endl;
}