Question

I have a class that holds an array of elements, and I want to give it a GetSize member function. But what return type should I give that function?

I'm using the pimpl idiom, and so in the header file it is not known what the implementation will use to store the elements. So I cannot just say std::vector<T>::size_type, for example:

class FooImpl;

class Foo {
  FooImpl* impl_;
public:
  TYPE GetSize(); // what TYPE??
};
Was it helpful?

Solution

If the client code can only see Foo (which is the purpose of pimpl idiom), then there's no use in define a specific size_type in the concrete implementation - it won't be visible/accessible to the client anyway. Standard containers can do that since they are built on so called "compile-time polymorphism", while you are specifically trying to use a [potentially] run-time implementation hiding method.

In your situation the only choice would be to choose an integer type that "should be enough for all possible implementations" (like unsigned long, for example) and stick with it.

Another possibility is to use the uintptr_t type, if it is available in your implementation (it is standardized in C99, but not in C++). This integer type is supposed to cover the entire storage address range available to the program, which means that it will always be sufficient for representing the size of any in-memory container. Note, that other posters often use the same logic, but incorrectly arrive at the conclusion that the appropriate type to use here is size_t. (This is usually a result of lack of experience with non-flat memory model implementatioons.) If your containers are always based on physical arrays, size_t will work. However, if your containers are not always array-based, size_t is not even remotely the correct type to use here, since its range is generally smaller than the maximum size of a non-continuous (non-array-based) container.

But in any case, regardelss of what size you are end up using, it is a good idea to hide it behind a typedef-name, just like it is done in standard containers.

OTHER TIPS

The generic type for sizes in C++ is size_t. I'd use that.

I mean generic in the non-technical sense. This has nothing to do with templates.

Looks like this came up before: When should I use std::size_t?

edit

After much discussion, I'm going to slightly amend my answer.

If the size_t is as wide as the pointer, use size_t. If not, use an unsigned int of the same width as the pointer.

size_type's are usually used to hide the integer type (short vs. long vs. long long etc). Just define your own Foo::size_type.

You could follow the STL's lead and make size_type a typedef that relies on FooImpl:

template<typename T> class s_type {
    public:
    typedef size_t type; // good default
};

class FooImpl;

// I'm only doing this specialization to show how it's done
// not because I think it's needed.  In general I'd use size_t.
template<> class s_type<FooImpl> {
    public:
    typedef uintptr_t type;
};

class Foo {
  FooImpl* impl_;

  public:
  typedef size_type s_type<FooImpl>::type;
  size_type GetSize();
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top