您正在查看: c++ 分类下的文章

15.5 Allocators in Detail

15.5 Allocators in Detail

According to the specified requirements, allocators have to provide the following types and operations. There are special requirements for allocators that can be used by the standard containers. Allocators that are not provided for the standard containers may have less requirements.

15.5.1
Type Definitions

allocator::value_type

<UL>
  • The type of the elements.

  • It is equivalent to T for allocator<T>.

        </lI>
    

    allocator::size_type

    <Ul>
    
  • The type for unsigned integral values that can represent the size of the largest object in the allocation model.

  • To be usable by the standard containers, this type must be equivalent to size_t.

        </LI>
    

    allocator::difference_type

    <ul>
    
  • The type for signed integral values that can represent the difference between any two pointers in the allocation model.

  • To be usable by the standard containers, this type must be equivalent to ptrdiff_t.

        </LI>
    

    allocator::pointer

    <UL>
    
  • The type of a pointer to the element type.

  • To be usable by the standard containers, this type must be equivalent to T* for allocator<T>.

        </li>
    

    allocator::const_pointer

    <ul>
    
  • The type of a constant pointer to the element type.

  • To be usable by the standard containers, this type must be equivalent to const T* for allocator<T>.

        </li>
    

    allocator::reference

    <UL>
    
  • The type of a reference to the element type.

  • It is equivalent to T& for allocator<T>.

        </lI>
    

    allocator::const_reference

    <Ul>
    
  • The type of a constant reference to the element type.

  • It is equivalent to const T& for allocator<T>.

        </LI>
    

    allocator::rebind

    <ul>
    
  • A template structure that provides the ability that any allocator may allocate storage of another type indirectly.

  • It has to be declared as follows:

    template <class T>
    class allocator {
    public:
    template <class U>
    struct rebind {
    typedef allocator<U> other;
    };
    ...
    }

        </LI>
    
  • See page 734 for an explanation of the purpose of rebind.

        </lI>
    

    15.5.2
    Operations

    allocator::allocator ()

    <ul>
    
  • The default constructor.

  • Creates an allocator object.

        </li>
    

    allocator::allocator (const allocator& a)

    <Ul>
    
  • The copy constructor.

  • Copies an allocator object so that storage allocated from the original and from the copy can be deallocated via the other.

        </LI>
    

    allocator::~allocator ()

    <ul>
    
  • The destructor.

  • Destroys an allocator object.

        </LI>
    

    pointer allocator::address (reference value)

    <p>const_pointer
        <b>allocator</b><B>::address</B> (const_reference
        value)</p>
    
    <ul>
    
  • The first form returns a nonconstant pointer to the nonconstant value.

  • The second form returns a constant pointer to the constant value.

        </li>
    

    size_type allocator::max_size ()

    <UL>
    
  • Returns the largest value that can be passed meaningfully to allocate() to allocate storage.

        </LI>
    

    pointer allocator::allocate (size_type num)

    <p>pointer
        <B>allocator</b><B>::allocate</B> (size_type num,
        allocator&lt;void>::const_pointer
        hint)</P>
    
    <UL>
    
  • Both forms return storage for num elements of type T.

  • The elements are not constructed/initialized (no constructors are called).

  • The optional second argument has an implementation-specific meaning. For example, it may be used by an implementation to help improve performance.

        </li>
    

    void allocator::deallocate (pointer p, size_type num)

    <UL>
    
  • Frees the storage to which p refers.

  • The storage of p has to be allocated by allocate() of the same or an equal allocator.

  • p must not be NULL or 0.

  • The elements have to have been destroyed already.

        </LI>
    

    void allocator::construct (pointer p, const T& value)

    <uL>
    
  • Initializes the storage of one element to which p refers with value.

  • It is equivalent to new((void*)p)T(value).

        </li>
    

    void allocator::destroy (pointer p)

    <UL>
    
  • Destroys the object to which p refers without deallocating the storage.

  • Simply calls the destructor for the object.

  • It is equivalent to ((T*)p)->T().

        </LI>
    

    bool operator == (const allocator& a1, const allocator& a2)

    <ul>
    
  • Returns true if allocators a1 and a2 are interchangeable.

  • Two allocators are interchangeable if storage allocated from each can be deallocated via the other.

  • To be usable by the standard containers, allocators of the same type are required to be interchangeable. So, this function should always return true.

        </li>
    

    bool operator != (const allocator& a1, const allocator& a2)

    <uL>
    
  • Returns true if two allocators are not interchangeable.

  • It is equivalent to ! (a1 == a2).

  • To be usable by the standard containers, allocators of the same type are required to be interchangeable. So, this function should always return false.

        </LI>
    
  • 15.6 Utilities for Uninitialized Memory in Detail

    15.6 Utilities for Uninitialized Memory in Detail

    This section describes the auxiliary functions for uninitialized memory in detail. The exemplary exception safe implementation of these functions is based with permission on code by Greg Colvin.

    void uninitialized_fill (ForwardIterator beg, ForwardIterator end,
    const T& value)

    • Initializes the elements in the range [beg,end) with value.

    • This function either succeeds or has no effect.

    • This function usually is implemented as follows:

      </li>
      

    namespace std {
    template <class ForwIter, class T>
    void uninitialized_fill(ForwIter beg, ForwIter end,
    const T& value)
    {
    typedef typename iterator_traits<ForwIter>::value_type VT;
    ForwIter save(beg);
    try {
    for (; beg!=end; ++beg) {
    new (static_cast<void>(&beg))VT(value);
    }
    }
    catch (...) {
    for (; save!=beg; ++save) {
    save->~VT();
    }
    throw;
    }
    }
    }

    void uninitialized_fill_n (ForwardIterator beg, Size num, const T& value)

    • initializes num elements starting from beg with value.

    • This function either succeeds or has no effect.

    • This function usually is implemented as follows:

          <PrE>
      

      namespace std {
      template <class ForwIter, class Size, class T>
      void uninitialized_fill_n (ForwIter beg, Size num,
      const T& value)
      {
      typedef typename iterator_traits<ForwIter>::value_type VT;
      ForwIter save(beg);
      try {
      for (; num--; ++beg) {
      new (static_cast<void>(&beg))VT(value);
      }
      }
      catch (...) {
      for (; save!=beg; ++save) {
      save->~VT();
      }
      throw;
      }
      }
      }

          </PRE>
      
      </LI>
      
    • See page 730 for an example of the use of uninitialized_fill_n().

      </LI>
      

    ForwardIterator uninitialized_copy (InputIterator sourceBeg,
    InputIterator sourceEnd,
    ForwardIterator destBeg)

    • Initializes the memory starting at destBeg with the elements in the range [sourceBeg,sourceEnd).

    • The function either succeeds or has no effect.

    • The function usually is implemented as follows:

          <PrE>
      

      namespace std {
      template <class InputIter, class ForwIter>
      ForwIter uninitialized_copy(lnputIter beg, InputIter end,
      ForwIter dest)
      {
      typedef typename iterator_traits<ForwIter>::value_type VT;
      ForwIter save(dest);
      try {
      for (; beg!=end; ++beg,++dest) {
      new (static_cast<void>(&dest))VT(*beg);
      }
      return dest;
      }
      catch (...) {
      for (; save!=dest; ++save) {
      save->~VT();
      }
      throw;
      }
      }
      }

      </LI>
      
    • See page 730 for an example of the use of uninitialized_copy().

      </li>
      

    Internet Resources

    Internet Resources

    The Internet is a huge source of information regarding the topic of this book. Here is a list of my recommendations of sites where you could find additional, relevant information.

    Chapter 15. Allocators

    Chapter 15. Allocators

    Allocators were introduced in Section 3.4. They represent a special memory model and are an abstraction used to translate the need to use memory into a raw call for memory. This chapter describes allocators in detail.

    15.1 Using Allocators as an Application Programmer

    15.1 Using Allocators as an Application Programmer

    For the application programmer, using different allocators should be no problem. You simply have to pass the allocator as a template argument. For example, the following statements create different containers and strings using the special allocator SpecialAlloc:

    // a vector with special allocator
    vector<int,SpecialAlloc> v;

    // an int/float map with special allocator
    map<int,float,less<int>,SpecialAlloc> m;

    // a string with special allocator
    basic_string<char,char_traits<char>,SpecialAlloc> s;

    If you use your own allocator, it probably is a good idea to make some type definitions. For example:

    // special string type that uses special allocator
    typedef basic_string<char,char_traits<char>,SpecialAlloc> xstring;

    // special string/string map type that uses special allocator
    typedef map<xstring,xstring,less<xstring>,SpecialAlloc> xmap;

    // create object of this type
    xmap mymap;

    When you use objects with other than the default allocator, you'll see no difference. However, beware that you don't mix elements with different allocators; otherwise, the behavior is undefined. You can check whether two allocators use the same memory model by using operator ==. If it returns true, you can deallocate storage allocated from one allocator via the other. To access the allocator, all types that are parameterized by an allocator provide the member function get_allocator(). For example:

    if (mymap.get_allocator() == s.get_allocator()) {
    //OK, mymap and s use the same or interchangeable allocators
    ...
    }