Should I open iterators and adapters or the whole container in C ++?

Consider a piece of code:

class Foo
{ // ...
    std::vector<Bar> bars;
};

      

Should I disclose the entire container, or should I expose 'iterator class and write adapter methods ( begin()

, end()

, size()

, and all that I need)?

If the answer depends on how you decide?

+2


source to share


6 answers


You only publish iterators or iterator-ranges (and typed iterator types) unless you absolutely need to expose the container.



This avoids breaking other code when you change implementation details, and follows the guidelines for hiding / encapsulating information.

+8


source


If you want to follow good design lines,

your card must be private or protected and it must look like



class Foo
{  
    public:
    typedef std::vector<Bar>::const_iterator FooIterator;
    FooIterator begin()
    {
      return bars.begin();
    }
    FooIterator end()
   {
    return bars.end();
   }
    protected:
    std::vector<Bar> bars;

};

int main()
{
   Foo obj;
   for(obj::FooIterator itr=obj.begin();itr!=obj.end();itr++)
  {
  }
}

      

+3


source


The answer is "It depends". :)

How much does your class user need to know about internal vector

?

Take a class stack

in the standard library as an example . It uses a standard container internally, but doesn't even expose to iterators. It provides push and pop methods, and a little more.

The user of the class does not need to know anything else. The user of the class should not be allowed to access the middle of the stack. If you do this, it is no longer a stack.

Quite often, users of a class really don't need anything more than iterators. If your class Foo

provides begin()

and end()

, what else do I need? I can access every element of the internal data structure as I please. I can change each of them or read each of them.

Do I need to insert / remove items as well? Perhaps, and if so, should I be doing this directly on the vector, or with your adapters? It depends. What is the object? Does it make sense to add objects directly to the owned vector Foo

? Or does it make sense to add objects to an object Foo

and let it delegate whatever internal implementation it likes?

+2


source


It depends.
If you change the state of the foo object when you change the state of pub in the container , you should not expose the container (as you can restrict access to it at a later stage, or write the hits).

If, on the other hand, foo objects are just a glorified container that also contains a vector, then perhaps exposing the vector is okay (note, maybe). Note, by exposing a vector that you tightly bind the user foo to the std :: vector and thus changing it to a different container type in the last step can be trickier.

+1


source


If you only need to read from your vector, output it .begin (). End () and an iterator. If you really need to add / remove data or change it, output the entire vector.

0


source


Don't expose nothin, wrap the call with thin wrapper methods, and check for some obvious ones like null and subscript outside, and type checks and sanity checks.

Look at the horrors of coding here on this site, why the coder in M ​​$ found his function call posted on ZD net as patch of the week. If you have to write hand-edited null results and expose them in other sections, you might get hit by section 8

0


source







All Articles