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

August 30, 2019 · View on GitHub

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'