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

  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!

  std::vector<Animal> mAnimals;


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








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.








  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