Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class design question - how to provide read only access to class member container [closed]

Tags:

c++

In my day-to-day work, I often find myself writing classes like in this simplified example:

class CGarage
{
public:
    CGarage();
    ~CGarage();
    typedef std::vector<Car> CarCollection;

private:
    CarCollection m_Cars;
};

I want the users of CGarage to have read only access to the CarCollection. In order to achieve that goal, those are some common solutions which are all not very satisfying:

Solution 1

class CGarage
{
    Car GetCar(CarCollection::size_type index) const;
    CarCollection::size_type CarCount() const;
};

Main disadvantage:

  • Lacking iterators, I can't use STL algorithms on Cars (e.g. for_each(...))

Solution 2

class CGarage
{
    CarCollection::const_iterator CarBegin() const;
    CarCollection::const_iterator CarEnd() const;
    CarCollection::size_type CarCount() const;
};

Main disadvantage:

  • A lot of boilerplate code if you need support for other iterator types (it, reverse_it).

Solution 3

class CGarage
{
    const CarCollection GetCars() const;
};

Main disadvantage:

  • cost of copying CarCollection when returning by value
  • implementation details known to users of class (e.g. can't change to std::list without change of breaking user code)

Solution 4

class CGarage
{
    const CarCollection& GetCars() const;
};

Main disadvantage:

  • lifetime of CarCollection reference bound to lifetime of CGarage
  • implementation details known to users of class

Questions

How would you provide read-only access to the CarCollection?

Does your solution change, if CarCollection is a vector with pointers to Car?

If you allow read and write access to the collection, is it acceptable to make the collection public?

Thanks for any advice

like image 430
nabulke Avatar asked Nov 20 '10 13:11

nabulke


2 Answers

How would you provide read-only access to the CarCollection?

I don't see what's wrong with solution 4. It should be obvious to users of CGarage that a reference to its car collection is tied to the lifetime of the garage. If they need the car collection to outlive the garage then they can always take a copy if they like.

Alternatively, make CGarage hold a shared_ptr to the car collection and return that, but I wouldn't recommend it.

Does your solution change, if CarCollection is a vector with pointers to Car?

For collections of owned objects (i.e. reference types), it is best to use a different container. The std:: containers are all designed for value types, and don't handle reference types very well (especially constness). For these, use something like Boost's ptr_vector.

If you allow read and write access to the collection, is it acceptable to make the collection public?

Depends on your specific situation. Are the semantics of the collection likely to change? If not, then you can safely make it public (e.g. std::pair). I wouldn't recommend that you do this for domain specific problem though.

like image 114
Peter Alexander Avatar answered Nov 14 '22 23:11

Peter Alexander


wouldn't it be sufficient to declare it like this?

const CarCollection& Cars() { return m_Cars; }

then

 CarCollection::const_iterator it = garage.Cars().begin();

should work but

  CarCollection::iterator it = garage.Cars().begin();

would give error.

like image 45
AndersK Avatar answered Nov 14 '22 22:11

AndersK