I am going to develop an API where there are two classes: a data / computation class and a container for this class. The container, however, is not just a mute container, but also contains information about the collection as a whole, which goes beyond the usual things that can be implemented using iterators.
Thus, the container basically wraps std::vector , adds some pre-calculated attributes, utility functions, etc. What the container class API should also contain is
- The method of adding instances of the data / calc class,
- access methods.
I just donβt want to open std::vector to the public, because adding a new data / calc class to the container causes recalculation of several attributes of the collection class. However, I want to provide an access method equal to the access methods of the STL at() and operator [] containers.
First, I added a private attribute of type std::vector<std::unique_ptr<DataClass>> . There is an addDataObject(DataObject *d) method that wraps the object in unique_ptr and updates the statistics.
However, the problem is with access methods: what will be their return type?
- Just returning
std::unique_ptr<DataClass> & doesn't seem like a clean API design: the API user does not need to know that I use smart pointers. (See also Herb Sutter presentation on C ++ 11) - Returning
DataClass *& not possible, especially not for operator [] , because I can access the raw pointer std::unique_ptr using the get() smart pointer method, which does not give me a link. - Returning a
DataClass & does not make sense, especially when I store pointers (allocation of heap and stack). - The return of a
DataClass * violates the principle of least surprise, because if the method is named in the sense of STL container access methods, one would expect it to return a link, especially for operator [] .
As an illustration, this will be a simplified example:
class DataClass { Container *m_parent; public: double someComplicatedCalculation(const double &input); }; class Container { std::vector<std::unique_ptr<DataClass>> m_collection; public: void addDataObject(DataClass *d); DataClass *&at(const int &index); const DataClass *&at(const int &index) const; DataClass *&operator [](const int &index); const DataClass *&operator [](const int &index) const; };
source share