7

It seems obvious to consider a string to be a vector of characters. Why then does string have its own special implementation, which seems quite different from that of the vector class?

Just to illustrate the point, here are some snippets from both classes to show that the work needed is rather similar, e.g. both using an allocator to manage memory. Also having traits could be useful for vectors as well.

The following snipped from the implementation of std::string looks like it would fit into the more general implementation of std::vector if we would allow a vector to have type-traits.

 139  template <class _charT, class _Traits , class _Allocator >                                        |
 140  class _RWSTDExportTemplate basic_string                                                           |
 141  {                                                                                                 |
 142  public:  
 ....
 333    size_type size () const   { return length(); }                                                  |
 334    inline size_type length () const;                                                               |
 335    size_type max_size () const                                                                     |
 336    {                                                                                               |
 337      return npos - sizeof(__rep_type)-2;                                                           |
 338    }                                                                                               |
 339    inline void resize (size_type, _charT);                                                         |
 340    void resize (size_type n)                                                                       |
 341    {                                                                                               |
 342      resize(n,__eos());                                                                            |
 343    }                                                                                               |
 344    inline size_type capacity () const;                                                             |
 345    inline void reserve (size_type=0);                                                              |
 346    void clear () { erase(); }                                                                      |
 347    bool empty () const  { return length() == 0; }   

And this is from vector:

75  template <class _Tt, class _Allocator _RWSTD_COMPLEX_DEFAULT(allocator<_Tt>) >                    |
76  class vector                                                                                      |
77  {                                                                                                 |
78       
86  public:                                                                                           |
87    //                                                                                              |
88    // Types.                                                                                       |
89    //                                                                                              |
90    typedef _Tt                                         value_type;                                 |
91    typedef _Allocator                                  allocator_type;                             |
92 
383    //                                                                                              |
384    // Capacity.
385    //
386    size_type size ()     const { return size_type(end() - begin()); }
387    size_type max_size () const { return __value_alloc_type(__end_of_storage).max_size();   }
388    void resize (size_type new_size);
389    void resize (size_type new_size, _Tt value);
390
391    size_type capacity () const { return size_type(__end_of_storage.data() - begin()); }
392    bool      empty ()    const { return begin() == end();                    }
393    void reserve (size_type n)
394    {
395      _RWSTD_THROW(n > max_size(), length_error,
396        __RWSTD::except_msg_string(__RWSTD::__rwse_InvalidSizeParam,
397          "vector::reserve(size_t)",n,max_size()).msgstr());
398
399      if (capacity() < n)
400      {
401        __value_alloc_type va(__end_of_storage);
402        iterator tmp = va.allocate(n,__start);
403#ifndef _RWSTD_NO_EXCEPTIONS
404        try {
405          uninitialized_copy(begin(), end(), tmp);
406        } catch(...) {
407          __value_alloc_type(__end_of_storage).deallocate(tmp,n);
408          throw;
409        }
410#else
Beginner
  • 5,277
  • 6
  • 34
  • 71

2 Answers2

3

Take for example this snippet:

string s = "abc";

There is no container that has a similar kind of initialisation syntax where it receives a pointer to the first element and scans the sequence for the special terminator element. Using a std::vector would be cumbersome at least. Since texts are common in computing, having a convenient text container type is simply a necessity and std::vector just doesn't fit.

That said, I could imagine std::string inheriting std::vector<char> privately or aggregating it, but that's a whole different issue than being a specialization of it. It also can't be a specialization, because what if you want a vector<char> that does not behave like a string? You would then have the same fubar as with vector<bool> today.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
2

A std::string has behavior that is not compatible with std::vector, in particular the appearance of a zero-value at the end.

C++11 §21.4.5/2 about operator[], in [string.access]:

Returns: *(begin() + pos) if pos < size(), otherwise a reference to an object of type T with value charT(); the referenced value shall not be modified.

Another big difference is that std::string supports the small buffer optimization, while that optimization possibility is not available for std::vector.

Community
  • 1
  • 1
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331