CS 509, Advanced Programming II

Spring 2002 - Test 6


  1. A colleague of yours can't remember whether the proper self-assignment test is this == &rhs or *this == rhs. Describe a handy way for your colleague to remember which is the better test (if one test is better than the other).


    The first test - this == &rhs - is a comparison between two pointers, which is correct, fast, efficient, and always defined. The second test - *this == rhs - is a comparison between two class instances. However, two instances having the same value does not imply that they're the same instance. In addition, operator ==() needs to be defined for the class, and if it is it's probably going to be much slower than a comparison between two pointers.

    Most people got this right, although many people didn't get it as right as they could have because they didn't justify their answer.


  2. Suppose you define a class A that uses no dynamic memory directly, but has member instances of a class B that does use dynamic memory. Do you need to define a copy constructor for class A, or is the default copy constructor good enough? Explain.


    The default copy-constructor for A is good enough. The default copy-constructor for A will call the copy-constructor defined for any member variables that have them, as member instances of class B do in this problem.

    Few got this exactly right, and some managed to dipsy-doodle around a reasonable answer. Many tried to answer this question with the rule of three, which has little relevance to this problem.


  3. One of the solutions discussed in class for the event * cast problem was to use the explicit keyword with the cast constructor so that

    event e = new event();
    

    would now have to be written.

    event e = static_cast<event>(new event());
    

    A colleague of yours, however, believes the cast should be a reinterpret-cast because it involves a pointer. What explanation do you give your colleague? You should ignore the garbage problem in your answer.


    There are at least two explanations you can give your colleague. First, while it's true the source of a reinterpret cast is a pointer, so is the target, which is not the case here.

    Second, a cast constructor, which the cast above was defined as, defines an implicit cast; that is, a static cast. If (non-explicit) cast constructors were some other kind of cast, the compiler couldn't use them implicitly.

    A lot of people got fatally distracted by the explicit keyword, which doesn't have a lot to do with the answer. A lot of reasonable answers weren't good answers because they just stated that static casts are correct without justification.


  4. The rule of three is one way of managing dynamic memory in classes to avoid problems with garbage, dangling pointers, and unexpected sharing. The graph-node class from the sixth assignment showed another way. How did the graph-node class manage dynamic memory and how did it differ from the rule of three?


    The graph-node class managed dynamic memory by making the assignment operator and copy constructor private, which prevents any other class but the graph-node class from accessing them.

    Because graph-nodes can be neither copied nor assigned, it is no longer necessary to worry about what happens to dynamic memory in either of those cases. (Strictly speaking, graph-nodes can still be copied and assigned within the graph-node class itself. However, within the class dynamic memory can be handled as appropriate, if it needs to be handled at all.)

    The dynamic memory in a graph-node still needs to be deallocated when the node is destroyed, so the class must implement a public destructor.

    Many people tried to answer this question using data_ptr or the pickleable class, but they don't have anything to do with the answer. Also, the rule of three was pretty well mangled in most answers, although a surprising number of answers didn't even include it.



This page last modified on 19 April 2002.