views:

387

answers:

6

I have a class with a private data member of type vector< A*>.

The class has two public methods that actually use vector::size_type:

  1. Method returning number of elements in the vector
  2. Method returning element in the vector by index

I can add to public section of the class the following typedef:

typedef vector::size_type SIZE_t;

but IMHO it exposes too many details about class implementation.

Another approach is to use size_t.

What do you think?

+2  A: 

Use plain old size_t for both member functions.

dirkgently
+2  A: 

Which details would those be? The only thing size_type exposes is the size needed for indexing (which will almost certainly be size_t). Adding the typedef doesn't expose any more information.

anon
IMO, the OP thinks the typedef exposes the fact that a `vector` is used under the hoods.
dirkgently
That's not what encapsulation is about though. Users still can't get at the vector, or make any assumptions about its implementation. But I agree with you about using size_t instead - but I must admit I'd use unsigned int myself - I hate names with underscores in them :-)
anon
IMHO, `size_t` is more readable -- it's screaming out "Look I represent a size of something" (and it is unsigned). ;-) YMMV
dirkgently
I would say that `size_type` is quite good at screaming out that it is a size. IMHO, the typedef actually helps encapsulation: user code does not need to know what type is being used, and the typedef can change without user code breaking (as long as they did use the typedef and not the concrete type)
David Rodríguez - dribeas
+1  A: 

All size_t types are fundamentally the same scalar type and since its scalar, it is implicitly convertible for the compiler. So there is no compile-time or runtime difference between using std::size_t, std::vector::size_type or any other similar type.

It is a good idea (and adhering to conventions) to provide a typedef for the size type in your class. IMO the typedef you show does not expose too much of your implementation, since clients are supposed to use your typedef, not vector::size_type directly. But if you prefer

typedef std::size_t SIZE_T;

that looks equally fine to me.

Péter Török
Apart from SIZE_T looks like a macro. But that just a style issue.
Martin York
Well, that was his choice not mine ;-)
Péter Török
+3  A: 

I would use a typedef in the class. The reason is that for std::vector, the size type is std::size_t, but if you later change the code to use a container (hand rolled) whose size type is not std::size_t redefining the typedef will be enough.

Using that typedef does not expose any detail of implementation, and it in fact helps encapsulate. The important element in the typedef is the local name, not what it is defined to be.

for ( mytype::size_type i = 0; i < myelement.size(); ++i )

In the for loop above, user code is unaware of whether size_type is a signed or unsigned type, it just works. You can change your implementation, and as long as you update the typedef the previous code will compile without signed/unsigned comparison warnings. The typedef actually helps encapsulation.

David Rodríguez - dribeas
+1  A: 

If you want to have the greatest level of encapsulation, then I would use:

private:
    typedef std::vector<A*> container_type;
    container_type _container;
public:
    typedef container_type::const_iterator const_iterator;

    const_iterator begin()const{ return _container.begin(); }
    const_iterator end()const{ return _container.end(); }

By using iterators instead of the size type, you would be able to switch between std::vector and std::list. However, if random access is a requirement for your class, then I would go with:

private:
    typedef std::vector<A*> container_type;
    container_type _container;
public:
    typedef container_type::size_type size_type;
    A* operator[](size_type idx)const{ return _container[idx]; }
    size_type size()const{ return _container.size(); }

If the user of your class does not need to be able to iterate through the contents of the internal container, then I would simply keep the typedefs private and not provide those public accessor functions.

Michael Aaron Safyan
A: 

If your class is already using std::vector<A*> in its implementation, then adding typedef std::vector<A*>::size_type size_type does not expose any more details than it already exposes.

However, if you are going for full encapsulation, you would want to a technique such as the PIMPL idom or an interface class (also known as protocol class), completely hiding that std::vector<A*> is used in the implementation at all:

Before:

#include <vector>
class A;
class Foo {
public:
    typedef std::vector<A*>::size_type size_type;
    size_type get_number_of_stuff() const;
private:
    std::vector<A*> _stuff;
};

After (using PIMPL technique):

class FooImpl;
class Foo {
public:
    typedef size_t size_type; // or just use size_t directly below
    size_type get_number_of_stuff() const;
private:
    FooImpl* _impl;
};

FooImpl is defined in your source file, not the header, completely hiding the choice of vector in the implementation details. Therefore, you no longer need to #include <vector> in your header file anymore, which has a couple benefits:

  • Users of your header file don't have to (indirectly) include vector if they don't use it. This can improve compile-time performance, which is important in larger code bases.
  • If you change the implementation (e.g., to list), you don't risk breaking any code that (erroneously) relied on your #include <vector>, which is now #include <list>. It happens.
Jason Govig
But with PIMPL you don't use std::vector<A*>::size_type any more, but use size_t instead. What if I still want to use exact size of container (std::vector<A*>::size_type), than it brings vector/list to user code.
dimba
@idimba: STL containers generally use size_t for size_type, so using size_t is a safe alternative. It also scales properly for 32-bit vs. 64-bit (as opposed to using int, unsigned int, etc.) However, if you still want to use `std::vector<A*>::size_type` as a basis, then you must at least `#include <vector>` and forward declare `class A`, even if you use a typedef to help hide that.
Jason Govig