Gcc4.7.0 database, a brief explanation of the changes brought about by C ++ 11

Source: Internet
Author: User

I have been practicing for 2 months. in this article, I would like to remember the summer vacation I used for my internship. t_t)

Start:

 

Simply put, vector inherits _ vector_base, which can be implemented in two layers. In _ vector_base, operations related to memory allocation are encapsulated, such as _ m_allocate () and _ m_deallocate () in _ vector_base, there is a built-in structure called _ vector_impl. It contains three pointers pointing to the start, end, and current usage of the memory area respectively. this is the implementation of vector. All operations are carried out around the three pointers, which are simple and clear. _ m_allocate (), _ m_deallocate () is actually encapsulation of the Allocator application (Allocator () and release (deallocator () interfaces.

When looking at Hou Jie's source code analysis, he first talked about allocator. the Allocator used by the sgi stl uses the memory pool technology, which may increase the allocation efficiency. in the GCC library implementation, the Allocator used by default is the simplest new Allocator, the reason for not using Allocator with memory pool can be found here http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt04ch11.html
In fact, many Allocator instances are provided in the GCC library, so you have the opportunity to learn more.

 

 

 

Pointer is defined as follows:

      typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template        rebind<_Tp>::other _Tp_alloc_type;      typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer       pointer;

Because vector is not an intrusive container, rebind <_ TP> is irrelevant. The intrusive container mainly talks about the relationship between the applied memory structure and T. For example, vector <t> the applied memory is the T array, which remains unchanged. However, for containers like list <t>, when applying for memory, except for the main type T, we also need two additional pointers pointing to the subsequent nodes of the leading node, which can be imagined as memory intrusion, two pointers are added (T and 2 extra pointers), but t is used when we pass in the template parameters. It has nothing to do with the two additional pointers. here we need rebind to rebind the type we need to apply. add additional information. _ alloc_traits <>: pointer extracts pointer types based on allocator.

Some major changes related to c ++ 11 are:

Add the move constructor to optimize the construction of the right value reference, as shown in figure

#ifdef __GXX_EXPERIMENTAL_CXX0X___Vector_impl(_Tp_alloc_type&& __a): _Tp_alloc_type(std::move(__a)),  _M_start(0), _M_finish(0), _M_end_of_storage(0){ }#endif
#ifdef __GXX_EXPERIMENTAL_CXX0X__      _Vector_base(_Tp_alloc_type&& __a)      : _M_impl(std::move(__a)) { }      _Vector_base(_Vector_base&& __x)      : _M_impl(std::move(__x._M_get_Tp_allocator()))      { this->_M_impl._M_swap_data(__x._M_impl); }      _Vector_base(_Vector_base&& __x, const allocator_type& __a)      : _M_impl(__a)      {if (__x.get_allocator() == __a)  this->_M_impl._M_swap_data(__x._M_impl);else  {    size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start;    _M_create_storage(__n);  }      }#endif

The internal implementation of _ m_swap_data () is to use the values of the three pointers of STD: swap exchange _ vector_impl to complete the move construction.

#ifdef __GXX_EXPERIMENTAL_CXX0X__      /**       *  @brief  Creates a %vector with default constructed elements.       *  @param  __n  The number of elements to initially create.       *       *  This constructor fills the %vector with @a __n default       *  constructed elements.       */      explicit      vector(size_type __n)      : _Base(__n)      { _M_default_initialize(__n); }      /**       *  @brief  Creates a %vector with copies of an exemplar element.       *  @param  __n  The number of elements to initially create.       *  @param  __value  An element to copy.       *  @param  __a  An allocator.       *       *  This constructor fills the %vector with @a __n copies of @a __value.       */      vector(size_type __n, const value_type& __value,     const allocator_type& __a = allocator_type())      : _Base(__n, __a)      { _M_fill_initialize(__n, __value); }#else      /**       *  @brief  Creates a %vector with copies of an exemplar element.       *  @param  __n  The number of elements to initially create.       *  @param  __value  An element to copy.       *  @param  __a  An allocator.       *       *  This constructor fills the %vector with @a __n copies of @a __value.       */      explicit      vector(size_type __n, const value_type& __value = value_type(),     const allocator_type& __a = allocator_type())      : _Base(__n, __a)      { _M_fill_initialize(__n, __value); }#endif

The constructor of the old vector (size_type N) uses the default parameter. If the constructor does not provide the constructed value, it uses the default value_type () for construction, in C ++ 11, the two functions are distinguished (two functions are declared). The internal implementation calls _ m_default_initialize () and _ m_fill_initialize () respectively (), they should be separated by efficiency optimization.

Not only does the constructor support right value reference, but it also contains the value assignment operator overload. c ++ 11 brings the initialization list, which is also reflected in constructor and value assignment overload, for example (not all listed)

      /**       *  @brief  Builds a %vector from an initializer list.       *  @param  __l  An initializer_list.       *  @param  __a  An allocator.       *       *  Create a %vector consisting of copies of the elements in the       *  initializer_list @a __l.       *       *  This will call the element type's copy constructor N times       *  (where N is @a __l.size()) and do no memory reallocation.       */      vector(initializer_list<value_type> __l,     const allocator_type& __a = allocator_type())      : _Base(__a)      {_M_range_initialize(__l.begin(), __l.end(),    random_access_iterator_tag());      }      /**       *  @brief  %Vector list assignment operator.       *  @param  __l  An initializer_list.       *       *  This function fills a %vector with copies of the elements in the       *  initializer list @a __l.       *       *  Note that the assignment completely changes the %vector and       *  that the resulting %vector's size is the same as the number       *  of elements assigned.  Old data may be lost.       */      vector&      operator=(initializer_list<value_type> __l)      {this->assign(__l.begin(), __l.end());return *this;      }

In terms of the iterator, C ++ 11 provides several interfaces for returning the const iterator, including cbegin (), Cend (), crbegin (), and crend (). at the same time, a data () interface is provided to obtain the first address of the memory area. If you want to obtain the first address of the vector memory area before, it should be & (* begin ()), because there is no way to ensure that the vector iterator is a pointer, We Need To unreference it first and then go to the address. The data () interface encapsulates related operations.

      // _GLIBCXX_RESOLVE_LIB_DEFECTS      // DR 464. Suggestion for new member functions in standard containers.      // data access      /**       *   Returns a pointer such that [data(), data() + size()) is a valid       *   range.  For a non-empty %vector, data() == &front().       */#ifdef __GXX_EXPERIMENTAL_CXX0X__      _Tp*#else      pointer#endif      data() _GLIBCXX_NOEXCEPT      { return std::__addressof(front()); }#ifdef __GXX_EXPERIMENTAL_CXX0X__      const _Tp*#else      const_pointer#endif      data() const _GLIBCXX_NOEXCEPT      { return std::__addressof(front()); }

C ++ 11 provides a shrink_to_fit interface to reduce redundant memory space. previously, we needed to use a vector like <t> (V ). swap (v) is used to release unused memory. Reserve () does not have any effect when the input value is smaller than the current capacity.

#ifdef __GXX_EXPERIMENTAL_CXX0X__      /**  A non-binding request to reduce capacity() to size().  */      void      shrink_to_fit()      { _M_shrink_to_fit(); }#endif

C ++ 11 has two new interfaces, emplace_back () and emplace ();

#ifdef __GXX_EXPERIMENTAL_CXX0X__      void      push_back(value_type&& __x)      { emplace_back(std::move(__x)); }      template<typename... _Args>        void        emplace_back(_Args&&... __args);#endif#ifdef __GXX_EXPERIMENTAL_CXX0X__      /**       *  @brief  Inserts an object in %vector before specified iterator.       *  @param  __position  An iterator into the %vector.       *  @param  __args  Arguments.       *  @return  An iterator that points to the inserted data.       *       *  This function will insert an object of type T constructed       *  with T(std::forward<Args>(args)...) before the specified location.       *  Note that this kind of operation could be expensive for a %vector       *  and if it is frequently used the user should consider using       *  std::list.       */      template<typename... _Args>        iterator        emplace(iterator __position, _Args&&... __args);#endif

I think emplace should be a move version of insert, and emplace_back is the move version of push_back. in the TCC file, stl_vector.h is just a Forward Declaration. the declaration of these two interfaces uses the new features of C ++ 11, the variable template (template variable), similar to printf (...) variable parameters, but this is used in the template. The Compiler provides support for this core feature. The processing method is actually to put it bluntly, recursive processing is performed one by one, finally, a template function with an empty template parameter is required to end recursive matching. (printf uses va_list-related items, we can use a variable template to implement a type-safe printf. If you are interested, you can find this document Andrei.
Alexandrescu's <variadic templates> PPT, if you have a strong search capability, there is actually a related speech video, In the channel9 of msdn, enough keywords, right? ^_^ ). the specific implementation is actually to construct a temporary object by passing in the corresponding constructor parameters. Because it is a temporary object, we press it to the vector by moving, in this way, the efficiency is improved (imagine a complicated object), compared to copying it again after the previous structure. the progress here is not only to call the default constructor, but to add STD: Forward <> (perfect forwarding) to the support of variable templates ), we can construct any object, not just the default constructor. Many changes are reflected in efficiency. the inherent disadvantage of STL is copy. After the move semantics is added, try to move as much as possible to improve efficiency. the Code is as follows:

#ifdef __GXX_EXPERIMENTAL_CXX0X__  template<typename _Tp, typename _Alloc>    template<typename... _Args>      void      vector<_Tp, _Alloc>::      emplace_back(_Args&&... __args)      {if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)  {    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,     std::forward<_Args>(__args)...);    ++this->_M_impl._M_finish;  }else  _M_emplace_back_aux(std::forward<_Args>(__args)...);      }#endif#ifdef __GXX_EXPERIMENTAL_CXX0X__  template<typename _Tp, typename _Alloc>    template<typename... _Args>      void      vector<_Tp, _Alloc>::      _M_emplace_back_aux(_Args&&... __args)      {const size_type __len =  _M_check_len(size_type(1), "vector::_M_emplace_back_aux");pointer __new_start(this->_M_allocate(__len));pointer __new_finish(__new_start);__try  {    _Alloc_traits::construct(this->_M_impl, __new_start + size(),     std::forward<_Args>(__args)...);    __new_finish = 0;    __new_finish      = std::__uninitialized_move_if_noexcept_a      (this->_M_impl._M_start, this->_M_impl._M_finish,       __new_start, _M_get_Tp_allocator());    ++__new_finish;  }__catch(...)  {    if (!__new_finish)      _Alloc_traits::destroy(this->_M_impl, __new_start + size());    else      std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());    _M_deallocate(__new_start, __len);    __throw_exception_again;  }std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,      _M_get_Tp_allocator());_M_deallocate(this->_M_impl._M_start,      this->_M_impl._M_end_of_storage      - this->_M_impl._M_start);this->_M_impl._M_start = __new_start;this->_M_impl._M_finish = __new_finish;this->_M_impl._M_end_of_storage = __new_start + __len;      }#endif
#ifdef __GXX_EXPERIMENTAL_CXX0X__  template<typename _Tp, typename _Alloc>    template<typename... _Args>      typename vector<_Tp, _Alloc>::iterator      vector<_Tp, _Alloc>::      emplace(iterator __position, _Args&&... __args)      {const size_type __n = __position - begin();if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage    && __position == end())  {    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,     std::forward<_Args>(__args)...);    ++this->_M_impl._M_finish;  }else  _M_insert_aux(__position, std::forward<_Args>(__args)...);return iterator(this->_M_impl._M_start + __n);      }  template<typename _Tp, typename _Alloc>    template<typename... _Args>      void      vector<_Tp, _Alloc>::      _M_insert_aux(iterator __position, _Args&&... __args)

The rest of the other things should be slightly different from the STL source code analysis of Hou jiepan. there may be some changes in details, but the overall idea is no problem. The Book of Hou jiepot has modified the source code to facilitate reading, reading the GCC library directly is really a little tricky. however, if you look a little more, you will get used to it. some naming rules can also be found. For example, _ m is actually a member function, and _ S is a static function. generally, _ is used internally, rather than exposed interfaces. finally, it should be noted that I have not listed all the source code changes in C ++ 11, and basically all the unposted constructors, copy constructors and assign values to those that are supported by the move semantics. some detailed functions are not listed. if you want to learn more, take a look at the source code, in the bits directory, stl_vector.h, vector. TCC. By default, allocator is * _ Allocator in the ext directory. h file, as shown in the figure above.

Array is only supported by static arrays added to C ++ 11. It provides some convenient interfaces for allocating memory from the stack, the effect is the same as that of t a [n. the interesting thing is that array supports the input parameter length of 0 to construct an array. in implementation, this situation is distinguished as follows:

      // Support for zero-sized arrays mandatory.      value_type _M_instance[_Nm ? _Nm : 1];
      reference       back()      { return _Nm ? *(end() - 1) : *end(); }

Added support for tuple-related interfaces to the array, specifically implemented through partial template features.

//1).tuple_size<array>::value  template<typename _Tp, std::size_t _Nm>    struct tuple_size<array<_Tp, _Nm>>    : public integral_constant<std::size_t, _Nm> { };//2).tuple_element<array>::type  template<std::size_t _Int, typename _Tp, std::size_t _Nm>    struct tuple_element<_Int, array<_Tp, _Nm> >    { typedef _Tp type; };//3).get<N>(array)  template<std::size_t _Int, typename _Tp, std::size_t _Nm>    constexpr _Tp&    get(array<_Tp, _Nm>& __arr) noexcept    { return __arr._M_instance[_Int]; }  template<std::size_t _Int, typename _Tp, std::size_t _Nm>    constexpr _Tp&&    get(array<_Tp, _Nm>&& __arr) noexcept    { return std::move(get<_Int>(__arr)); }

Array also provides the data () interface to return the first address of the memory. because it is a static array, array does not provide too many complex interfaces. only the iterator-related interfaces, such as size () and data (), and the related comparison operators are reloaded for ease of use.

At the end of the discussion: I saw Dr. Haos last night and saw Cameron and Chase get married. Suddenly I wanted to find a sister paper.-____-, okay, maybe it's because I recently lived with a fat app)

PS: At half past one last night, I found a fat player playing 3C and playing with a computer (3C is not as AI as Dota, but he is still playing ....).. suddenly I felt an egg of sorrow .....

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.