Access Functions for Containers with std :: unique_ptr

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; /* ... other member attributes/parameters ... */ public: /* A method that calculates something based on the attributes: */ double someComplicatedCalculation(const double &input); }; class Container { std::vector<std::unique_ptr<DataClass>> m_collection; /* more attributes: maintenance info, precomputed values, etc. */ public: void addDataObject(DataClass *d); /* What would the right return type be? */ DataClass *&at(const int &index); const DataClass *&at(const int &index) const; DataClass *&operator [](const int &index); const DataClass *&operator [](const int &index) const; }; 
+6
source share
2 answers

Its always difficult when you do not know all the details, but here is what I think:

  • Just returning std::unique_ptr<DataClass> & doesn't seem to be 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)

Definitely yes.

  • Returning a DataClass *& not possible, especially not for operator [] , because I can only access the raw pointer std::unique_ptr using the get() smart pointer method, which does not give me a link.

Really.

  • Returning a DataClass & does not make sense, especially when I store pointers (allocation of heap and stack).

It makes sense. What, in my opinion, does not make sense is to keep pointers for starters. A std::vector still saves everything on the heap, so if the reason for using pointers is, this does not apply.

  • Returning a DataClass * violates the principle of least surprise, because if a method is named in the sense of STL by a container, you can expect it to return a link, especially for operator [] .

Really.

I would say that you should return DataClass& . You probably shouldn't use pointers in your std::vector , but if you should use them, you can make your accessors, for example:

 DataClass& operator[](std::size_t index) { return *m_collection[index]; } 

But it would be better not to use pointers:

 class Container { std::vector<DataClass> m_collection; DataClass& operator[](std::size_t index) { return m_collection[index]; } // ... }; 
+1
source

Returning a DataClass & does not make sense, especially when I store pointers (allocation of heap and stack).

I do not agree. This is what all standard containers return. If the fact that you are using unique_ptr is something that should be visible to users (and I guess it shouldn't), then the path of least surprise would be to simply do as the standard library does: return lvalue reference to the object.

In addition, when returning the certificate, ownership becomes clear. If you want to return a pointer, you need to indicate somewhere that the user should not delete it.

+2
source

Source: https://habr.com/ru/post/986003/


All Articles