5
$\begingroup$

I am teaching destructors in C++ and would like to give the students an interesting homework exercise that requires them to build a class with destructor.

In previous years, the homework were something like "write a linked list, but do not use the classes in the STL". I do not like this - I tell my students that they can use whatever feature of the language that they want, even if we did not learn it in class yet.

The problem is, for every other exercise that I could think of (e.g, tree, graph, etc.) I could easily think of a solution using STL features, that does not require any destructor.

What is an interesting exercise where destructors are really needed?

$\endgroup$
4
  • $\begingroup$ Google for RAII. $\endgroup$ Mar 16, 2018 at 18:35
  • 1
    $\begingroup$ Your difficulty is thinking about in-memory data structures only. Chose examples where the objects provide a service, and have something to do when they are "leaving" (sending a shutdown notification through the network, for example). $\endgroup$ Mar 19, 2018 at 9:46
  • $\begingroup$ @MichelBillaud I did not understand. Can you expand? $\endgroup$ Mar 19, 2018 at 9:47
  • $\begingroup$ @ErelSegal-Halevi I mean, trees, graphs, etc. are merely containers for data, and can be built from basic containers from the standard library. So no surprise you can have RAII managing their destruction. Now a "Logger" object writing to a file. It should write a message when it is closed. Explicitely or by the destructor. $\endgroup$ Mar 19, 2018 at 11:06

5 Answers 5

4
$\begingroup$

Create an object that creates a new file and writes in to it over several method invocations (not just one). Assure that the object has been deleted before continuing (Make the object go out of scope on the stack or delete a reference and let the reference go out of scope.) You need to assure that he file was closed. The destructor is the proper place to assure that this happens.

To verify that it works correctly, create a different object that reads from the file. If the first object didn't properly close the file this won't be possible.

In some, at least, operating systems you don't even need the second part. The file won't appear in the file system if it was never closed.

The reason for wanting the file written over several invocations of some method(s) is that, if it is just one, an explicit close would be natural in that method. The reason for wanting any references to go out of scope is to assure you that the first object has no effect on the second.


Edited for clarification.

$\endgroup$
6
  • $\begingroup$ Good. It will also let them see that destructors are not only for memory management. But, don't the file-stream objects of the STL close the file automatically when they go out of scope? $\endgroup$ Mar 16, 2018 at 12:33
  • $\begingroup$ Yes, if you use such an object, since it has its own destructor. But you can open files otherwise. Any resource held should be released in a destructor if it can't be immediately released. See: learncpp.com/cpp-tutorial/8-7-destructors. So your problem (illustrating...) gets harder if everything you use is already properly built. Actually, you can allocate anything for any purpose. Release it in the destructor. Oh. And don't call any destructor twice (implicitly or otherwise). Very bad bug. $\endgroup$
    – Buffy
    Mar 16, 2018 at 12:39
  • $\begingroup$ @Buffy What OS does not write until close? I know that the file is not guaranteed written until you call flush or close. 2nd setting a pointer to null in C++ WILL NOT call the destructor; you have to use delete. It is not a garbage collected language. Unless you use smart pointers, with the appropriate code. $\endgroup$ Mar 16, 2018 at 13:20
  • $\begingroup$ If STL does this, then what about a class that uses malloc/new? $\endgroup$ Mar 16, 2018 at 13:21
  • $\begingroup$ @ctrl-alt-delor, I was just describing how to make the object go out of scope, nothing more. I understand that setting to null doesn't invoke the destructor. I don't understand the most recent comment. $\endgroup$
    – Buffy
    Mar 16, 2018 at 13:26
3
$\begingroup$

There are 2 good examples of patterns where the destuctor is a key.
This way you can teach a couple of useful patterns on the way.

RAII - Resource Acquisition Is Initiation

Rule of 3/5/0

It's easy to give a RAII assignment, just any C style handle that can be released in the end (Like a File handle, windows handle, etc).

If they are more advanced, you can try and teach about shared pointer implementation and have them attempt that (which could get tricky if you want to go into thread safety, etc.

$\endgroup$
1
  • $\begingroup$ Welcome to Computer Science Educators! Those resources might be great, but if you could include, in your answer, what they contain, they would be far more useful $\endgroup$
    – ItamarG3
    Mar 18, 2018 at 19:05
1
$\begingroup$

I'm not a native of C++, but it seems to me that a Conway's Game of Life simulator, with cells as immutable objects, would be a great way to show the need for a destructor. Without one, your program would quickly run out of memory.

And, of course, it's not a bad approach to the problem. All you'd have to do to demonstrate why such an approach is reasonable is to first try the naive approach of modifying the active gameboard to figure out the next turn. This, of course, always leads to incorrect behaviors, since the modification of one cell will be used in the calculation of the next cell.

One final advantage is that you will also be introducing your students to an important and interesting other algorithm in its own right.

$\endgroup$
4
  • $\begingroup$ This idea sounds very interesting and fun. I am trying to work out the details. $\endgroup$ Mar 16, 2018 at 12:38
  • $\begingroup$ hmm... on second thought, I think this requires explicit deletion by the programmer, rather than a destructor in the clas.. $\endgroup$ Mar 16, 2018 at 13:10
  • 2
    $\begingroup$ Releasing the memory occupied by a Foobar instance is not the responsibility of the class's destructor. The destructor gets called before the memory is released. It's responsibility is to release other resources---to free other objects, to close open files, etc.---that were "owned" by the Foobar object. $\endgroup$ Mar 16, 2018 at 18:39
  • $\begingroup$ I can imagine the simulation being updated with buffers and not needing deletion at all, however, it might be possible to design the class that represents the game board (or a chunk of the board) to free memory in its destructor leaving no need for an explicit delete operation, just an operation to break the game loop and let main() end. $\endgroup$ Nov 10, 2018 at 4:03
1
$\begingroup$

A separate approach entirely from my other answer is to code the main method of a project yourself, but ask your students to build the classes that will make your main method accomplish its task. This actually opens back up projects like linked lists, as your main will use a slightly different spec than the natural C++ library in any case.

Just include calls to the destructors of the classes when appropriate, and your project will quite naturally require destructors. And if your project requires any substantial amount of composition, failure to use destructors properly across the project will cause the program to run out of memory. Thus, you will be modeling the need first by directly calling destructors, and secondarily in a way that causes them to see the need themselves, with the students having to both design and call the relevant destructors for objects held through composition.

$\endgroup$
5
  • $\begingroup$ Cute. A bit devious, but cute. Good catch. $\endgroup$
    – Buffy
    Mar 16, 2018 at 12:28
  • $\begingroup$ Is it common to call destructors directly in C++? $\endgroup$ Mar 16, 2018 at 12:35
  • $\begingroup$ @ErelSegal-Halevi You've got me, I could be barking up the wrong tree. I'm a Java guy. I assumed that they were C++'s way to deallocate objects and that they had to be called, just like constructors. Upon examining the question now, it seems like I was mistaken about that part. However, this appears to be an interesting case when a destructor should be manually called. However, it might be out of scope of your course. $\endgroup$
    – Ben I.
    Mar 16, 2018 at 12:39
  • $\begingroup$ Normally the delete operator on a pointer invokes the destructor. It is rare (very) that destructors are invoked directly. $\endgroup$
    – Buffy
    Mar 16, 2018 at 14:03
  • $\begingroup$ @Buffy but you suggest that going out of scope, causes the destructor to be called, and that setting pointer to null, causes it to go out of scope. Only calling delete, or being automatic (stack semantics) and going out of scope will cause destructor to run (and object to be freed). $\endgroup$ Mar 16, 2018 at 19:30
0
$\begingroup$

OK, here is an idea.

Write a class Member that keeps track of members in a social network. Each member can follow/unfollow other members and know how many people he/she follows/followed by. Additionally the system keeps track of the number of active members.

Here is a sample main program:

Member avi, beni, chana;

void test1() {
    Member dana;
    chana.follow(dana);
    dana.follow(avi);
    cout << "  " << chana.numFollowers() << " " <<  chana.numFollowing() << endl; // 0 1
    cout << "  " << avi.numFollowers() << " " <<  avi.numFollowing() << endl; // 1 0
    cout << "  " << Member::count() << endl; // 4
}

int main() {
    cout << chana.numFollowers() << " " <<  chana.numFollowing() << endl; // 0 0
    test1();
    cout << chana.numFollowers() << " " <<  chana.numFollowing() << endl; // 0 0
    cout << avi.numFollowers() << " " <<  avi.numFollowing() << endl; // 0 0
    cout << Member::count() << endl; // 3
}

What do you think?

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.