Demetator law or return of the whole vector

Which one is better:

public: const vector<int> & GetPointsVector(); private: vector<int> PointsVector; 

Or:

 public: int GetCurrentPoint(); void MoveToFirstPoint(); void MoveToNextPoint(); bool IsAtLastPoint(); size_t GetNumberOfPoints(); private: vector<int> PointsVector; 
+4
source share
5 answers

There is no correct answer. The answer will vary depending on the context, of which we currently have very few.

It depends on the customers of your class. In most situations, you do not need a random inspector to change the state of the object, so to some extent it is better to return a reference to the const object. However, in this case, I would also make a const i.e.

  /* a design const - this accessor does not change the state */ const vector<int> & GetPointsVector() const; 

This is also effective since you don't go around heavy objects as return values ​​(this is another question that most compilers do RVO these days).

If your client needs to use a vector in algorithms, yes, you better provide iterators. But two pairs, i.e.

 typedef vector<int>::iterator _MyItr; _MyItr begin() const; _MyItr begin(); _MyItr end() const; _MyItr end(); 

This will be consistent with how the STL is designed. But be careful when specifying which iterator the client can expect (for example: if the class specification says the returned iterators are RandomIterators , it sets a certain number of expectations in your implementation).

+2
source

Both are not. Better return the begin () and end () iterators, or even better :: boost :: range for the iterator.

 private: typedef std::vector<int> PointsContainer; public: typedef boost::iterator_range<PointsContainer::const_iterator> PointsRange; PointsRange getPointsRange() const { return boost::make_iterator_range(pointsContainer_.begin(), pointsContainer_.end()); } 

The advantage is that traversal logic is hidden inside a range / iterator

When using one of the options:

 int p; foreach(p, obj.getPointsRange()) { //... } 

otherwise

 C::PointsRange r = obj.getPointsRange(); for(C::PointsRange::iterator i = r.begin(); i != r.end(); ++i) { int p = *i; //... } 
+13
source

None. Make a function that needs such a deep knowledge of the internal elements of a class in a member function.

+2
source

In my opinion, the first alternative (strictly with the const keyword) is better, since then you can use standard interfaces to access vector elements (for example, iterators, etc.). The second option (i.e., dedicated access methods) is required only when you have no other way to protect your data from accidental changes.

+2
source

I prefer to encapsulate the internal representation of the data and use the public template function EachSomething. If you have an advantage, you can avoid the forEachSomething patterns and put the implementation in a .cpp file.

 class Class { public: Class() { points_.push_back( 1 ); points_.push_back( 5 ); points_.push_back( 7 ); } template <typename TFunction> void forEachPoint( TFunction function ) { std::for_each( points_.begin(), points_.end(), function ); } void forEachPoint2( boost::function< void (int ) > function ) { std::for_each( points_.begin(), points_.end(), function ); } private: std::vector<int> points_; }; void print( int a ) { std::cout << a << std::endl; } int main() { Class object; object.forEachPoint( print ); } 
0
source

All Articles