CSS 343: Notes from Lecture 13 (DRAFT)

Administrivia

Random Trivia

Recap

Delving Deeper into C++

C++ Classes

Constructor/Destructor

A substantial part of programming is about resource management. Resources include memory, open files, mutexes, etc.

It is important to be careful to note who owns an object in the documentation. Since this is an agreement between the library provider and library client, it is known as a contract. For example:

class Edge {
public:
  //...
  // Returns pointer to the from edge.
  // Valid as long as Graph is valid.
  Vertex* GetFrom();
private:
  //...
  Vertex* from_'
};

// Allocate new vertex.  Client is responsible for deleting.
Vertex* VertexFactory(const string& label);
	

C++ introduced constructors and destructors. The constructor ensures that an object is well-formed (all fields properly initialized). The destructor performs any required clean up.

For function-local objects, the destructor is called automatically when the code leave its scope. Destructors are called in reverse order of construction.

Resources may be managed using the constructor and destructor. This style of programming is known as RAII

For objects allocated on the heap (i.e. returned by new), the programmer is responsible for explicitly calling delete

Constructor: initialize base object, initialize members (in declaration order), then call constructor code:

#include <iostream>
#include <string>
using namespace std;

class Base {
public:
  Base(const string& s) : s_(s) {cout << "Base(" << s_ << ")\n";}
  ~Base() {cout << "~Base(" << s_ << ")\n";}
private:
  string s_;
};

class Member {
public:
  Member(const string& s) : s_(s) {cout << "Member(" << s_ << ")\n";}
  ~Member() {cout << "~Member(" << s_ << ")\n";}
private:
  string s_;
};

class Derived : public Base {
public:
  Derived(const string& s) :
    member2_("member 2"),
    s_(s),
    Base("base"),
    member1_("member 1")
    // Better style would be to initialize members in the order they occur:
    //   member1_("member 1"), member2_("member 2"), s_(s)
    // since that's the order they're initialized
  {
    cout << "Derived(" << s_ << ")\n";
  }
  ~Derived() {cout << "~Derived(" << s_ << ")\n";}
private:
  string s_;
  Member member1_;
  Member member2_;
};

int main() {
  Derived d("derived object");
  return 0;
}
	
Output:
Base(base)
Member(member 1)
Member(member 2)
Derived(derived object)
~Derived(derived object)
~Member(member 2)
~Member(member 1)
~Base(base)
	

Memory Management

Some languages, e.g. Java, implement garbage collection but it is not a panacea. Other languages, e.g. Python, use reference counting, also not a panacea.

C++ comes from C which was designed to work with low overhead on smaller systems, hence manual memory management.

Understanding manual memory management helps the software engineer avoid hitting the pitfalls of automatic memory management.

The destructor is used to ensure that resources are released.

smart pointers... operator overloading

Post-Midterm Review