CS 70

What About Data Members?

  • Duck speaking

    I think I'm feeling better about lifetime for individual objects, but what about data members?

  • LHS Cow speaking

    What about them?

  • Duck speaking

    Like, what if one class has an instance of another class as one of its data members?

  • Dog speaking

    Mind. Blown. 🤯

  • LHS Cow speaking

    Data members get their object-lifetime cues from the object that they're part of.

  • RHS Cow speaking

    Let's walk through what happens!

Allocation Phase

The space for data members is allocated when the space for the object itself ls allocated.

  • LHS Cow speaking

    In fact, the space for an object is the space for its data members!

Initialization Phase

The data members of a class are initialized as the very first step in the object's own initialization phase.

Crucially, remember that the data members have to be initialized in the member initialization list at the top of the constructor.

  • RHS Cow speaking

    Anything not explicitly initialized in the initialization list will be default initialized/constructed!

  • LHS Cow speaking

    The data members are initialized in the order they're declared in the class. The member initialization list should be in the same order. If it isn't, you'll probably get a compiler warning letting you know.

Use Phase

The data members of a class are used through the member functions of the class, or sometimes directly if they are public.

Destruction Phase

The data members of an object are destroyed when the object itself is destroyed, specifically, at the closing } of the destructor.

It destroys the data members in reverse order from the order they're declared in the class, thus the last data member constructed is the first one destroyed.

Crucially, the destructor that the compiler synthesizes is identical to a destructor with no code in the body. Given the rule above, it “does nothing” (the empty body) and then calls the destructor for each data member.

If that behavior is not sufficient, then you need to write a custom destructor.

  • RHS Cow speaking

    We'll see a situation where that's necessary in a future lesson!

Deallocation Phase

The data members are deallocated when the object is deallocated, since the memory for the data members is the memory for the object.

Practice Exercise

Suppose we have the Cow class from before, which has print statements in its constructors and destructor.

We'll make another class, Barn, that has a Cow as its only data member:

class Barn {
  public:
    Barn() = delete;
    Barn(const Cow& cow);
    Barn(const Barn& other) = default;
    ~Barn() = default;
  private:
    Cow residentCow_;
};

Barn::Barn(const Cow& cow) : residentCow_{cow} {
    // Nothing (else) to do
}

We then use the class in the following program:

int main() {
    Cow bessie;
    Barn olin{bessie};
    Barn moogregor{olin};
    return 0;
}

What will print when this program runs?

We'll get the following output:

Cow default constructor called
Cow copy constructor called
Cow copy constructor called
Cow destructor called
Cow destructor called
Cow destructor called

We can reason about the output like this:

  • The default constructor call is for bessie.
  • The first copy constructor call is for initializing the residentCow_ data member of olin as a copy of bessie.
  • The second copy constructor call is for initializing the residentCow_ data member of moogregor as a copy of olin's residentCow_.
  • The three destructor calls are for bessie, olin's residentCow_, and moogregor's residentCow_.
  • LHS Cow speaking

    Okay, we've made a lot of progress. Let's head up to the parent page to see what we've learned, and maybe take a break before we move on to our final chunk of material for this lesson.

(When logged in, completion status appears here.)