"Ben Pope" <benpope81@_REMOVE_gmail.com> wrote in message
news:1122250402.ba1ed96ef1ac23d9b40f5f5f364f5a1b@t eranews...[color=blue]
> Ben Pope wrote:[color=green]
>> Cy Edmunds wrote:
>>[color=darkred]
>>> I would give the user some iterators:
>>>
>>> template <typename T>
>>> class YourClass {
>>> public:
>>> typedef std::vector<T> t_container;
>>> typedef t_container::const_iterator const_iterator;
>>> const_iterator begin() const {return storage_.begin();}
>>> const_iterator end() const {return storage_.end();}
>>> ...
>>> };
>>>
>>> A smart client should be able to write his code in such a way that
>>> nothing breaks if you change to a different container type.[/color]
>>
>>
>> Hmm, interesting. I had toyed briefly with that idea, but hadn't
>> formulated any real ideas.
>>
>> I suppose the whole point is not to return the vector, giving access to
>> the iterators, but to return the iterators themselves.[/color][/color]
The point is to make your classes maintainable by not putting implementation
details (such as which container you decided to use) right at the interface.
For instance if you started with std::vector but later decided to switch to
ArrayStorage no client code should break.
[color=blue]
>
> Just for a laugh, say I wanted to implement that storage stuff as part of
> a policy, should I be doing something like the following?
>
> #include <vector>
>
> typedef unsigned short uint16;
> typedef unsigned char uint8;
>
> /**
> * Storage Policy based on a std::vector.
> */
> template<class T>
> class VectorStorage {
> public:
> typedef std::vector<T> t_container;
> typedef typename t_container::size_type size_type;
> typedef typename t_container::const_iterator const_iterator;
>
> const_iterator begin() const {return storage_.begin();}
> const_iterator end() const {return storage_.end();}
> private:
> t_container storage_;
> };
>
> /**
> * Storage Policy based on an array.
> */
> template<typename T>
> class ArrayStorage {
> public:
> typedef T* t_container;
> typedef uint16 size_type;[/color]
Hm, just wondering why you would limit your array size to 32K elements. I
would probably use size_t here.
[color=blue]
> typedef const T* const_iterator;
>
> ArrayStorage(size_type size = 8) : size_(size), storage_(new T[size])
> {}[/color]
You should declare this one explicit -- you don't really want automatic
conversion from uint16 to ArrayStorage<T>.
[color=blue]
> ~ArrayStorage() {delete[] storage_;}[/color]
Now you must include
ArrayStorage(const ArrayStorage<T> &);
and
ArrayStorage &operator = (const ArrayStorage<T> &);
Otherwise innocent looking code like
ArrayStorage<int> a1(3);
ArrayStorage<int> a2(a1);
will cause undefined behavior when storage_ gets deleted twice. Boost has a
reference counted smart pointer for arrays which might do what you want as
far as copy semantics are concerned.
[color=blue]
>
> const_iterator begin() const {return storage_;}
> const_iterator end() const {return storage_ + size_;}
> private:
> size_type size_;
> t_container storage_;
> };
>
> ...not that I'd want to use an array, usually, but if for some strange
> reason...
>
> That would seem to abstract my implementation of storage_ from the user of
> the class, wouldn't it?
>
> I could then publicly inherit either of those classes, and specify which
> one with a template parameter.[/color]
Better yet, you could encapsulate this object in your new object. This one
wasn't really made as a base class. For instance, no virtual destructor. I
think encapsulation should generally be preferred over inheritance with a
concrete data type like this.
[color=blue]
>
> Cheers!
>
> Ben
> --
> I'm not just a number. To many, I'm known as a String...[/color]
--
Cy
http://home.rochester.rr.com/cyhome/