Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) Answer of exercise #3: Don't give away your internals, #0

 

This is part #0 of the answer of exercise #3: Don't give away your internals.

 

 

 

 

 

Part #0: checking your member function design

 

Let's start by defining a test suite. Note that the definitions are not needed, the compiler will give the warnings and errors needed already.

 

#include <vector>

struct Animal
{
  int mX; //It does not matter what mX is...
};

struct Zoo
{
  //The GetAnimals method to be

  private:
  std::vector<Animal> mAnimals;
};


int main()
{
  Zoo zoo;
  zoo.GetAnimals[0].mX = 123; //Must not compile!
}

 

For the GetAnimals member function, there are many possibilities:

 

These sixteen possible member functions are:

 

std::vector<Animal> GetAnimals() ;
const std::vector<Animal> GetAnimals() ;
std::vector<const Animal> GetAnimals() ;
const std::vector<const Animal> GetAnimals() ;
std::vector<Animal>& GetAnimals() ;
const std::vector<Animal>& GetAnimals() ;
std::vector<const Animal>& GetAnimals() ;
const std::vector<const Animal>& GetAnimals() ;
std::vector<Animal> GetAnimals() const;
const std::vector<Animal> GetAnimals() const;
std::vector<const Animal> GetAnimals() const;
const std::vector<const Animal> GetAnimals() const;
std::vector<Animal>& GetAnimals() const;
const std::vector<Animal>& GetAnimals() const;
std::vector<const Animal>& GetAnimals() const;
const std::vector<const Animal>& GetAnimals() const;

 

The first halve to be taken off the list of possiblities are those that return a copy of the std::vector of Animals. We don't need a copy of all those animals (imagine that a Zoo has millions of animals!). We do need to do is get a safe read-only reference to the animals (Note: perhaps later we will get back to this!).

 

The second halve to be taken off the list of possiblities are the non-const-methods. We intend to only read from the Animals, so it should not change our Zoo. It should also be possible to read the Animals from a const Zoo.

 

This leaves only four options left, which I'll give numbers from now on:

 

std::vector< Animal>& GetAnimals0() const;
const std::vector< Animal>& GetAnimals1() const;
std::vector<const Animal>& GetAnimals2() const;
const std::vector<const Animal>& GetAnimals3() const;

 

Now the real tests start, even before defining the GetAnimal member functions.

 

The following line must not compile:

 

zoo.GetAnimalsX()[0].mX = 123;

 

Three out of four correctly refrain from compiling, where GetAnimals0 just performs the unwanted modification. GetAnimals0 is marked as a potential source for bugs, and taken off our list.

 

With three member functions left in the race, it's time to define them:

 

const std::vector< Animal>& GetAnimals1() const { return mAnimals; }
std::vector<const Animal>& GetAnimals2() const { return mAnimals; } //Does not compile
const std::vector<const Animal>& GetAnimals3() const { return mAnimals; } //Does not compile

 

It appears that GetAnimals2 and GetAnimals3 do not compile. This is correct: we indeed give away a reference to a std::vector<Animal> instead of to a std::vector<const Animal>. If we want to return a std::vector<const Animal> then we need to make a copy of all those animals. Let's refrain from this (for now) and call GetAnimals1 the winner.

 

struct Zoo
{
  const std::vector<Animal>& GetAnimals() const { return mAnimals; } //Brilliant!

  private:
  std::vector<Animal> mAnimals;
};

 

Go to the answer of the follow-up question: Answer of exercise #3: Don't give away your internals, #1

 

 

 

 

 

Epilogue

 

The exercise is called 'Don't give away your internals' (after [1]). One of the points of this item was the question: 'What do you want to do with this information?'. If you want to use std::cout on the implementation of Zoo (that is, the std::vector of Animal), why not enable to use std::cout on Zoo itself? Think if you perhaps do not need the GetAnimals (or similar, as in your code) method after all.

 

 

 

 

 

References

 

  1. Herb Sutter, Andrei Alexandrescu. C++ coding standards: 101 rules, guidelines, and best practices. ISBN: 0-32-111358-6. Item 28: 'Don't give away your internals'

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict