简体   繁体   中英

How does smart pointer choose default_delete by partial specialization?

unique_ptr is basically implemented as follows:

template <typename _Tp>    // deleter for single object
struct default_delete {
  void operator()(_Tp* ptr) const {
    delete ptr;
  }
};
template <typename _Tp>    // deleter for array
struct default_delete<_Tp[]> {
  void operator()(_Tp* ptr) const {
    delete[] ptr;
  }
};

// main template
template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr {
public:
  typedef _Tp  element_type;
  typedef _Dp  deleter_type;
  // ...
};

// array specialized
template <typename _Tp, typename _Dp>
class unique_ptr<_Tp[], _Dp> {   
public:               // ^ How did this work?
  typedef _Tp  element_type;
  typedef _Dp  deleter_type;
  // ...
};

When I use int[] as template argument, obviously this will fall into unique_ptr's array version. As far as I know, compiler will match Tp[] with int[], and match Dp with the default template parameter default_delete<_Tp>>. So Tp is deduced to int, and finally the template parameter list deduced will be like this in my thought:

<int[], default_delete<int>>

My question: How did the compiler select default_delete's partial specialization for delete[] ? It seems like there is no reason to choose deleter's int[] version. I think parameter Dp in specialized version and in main template are the same.

_Tp in the primary template and _Tp in the partial specialization are not the same. You could give them different names to distinguish them better.

The default template arguments are taken from the primary template and this gives the default argument

default_delete<_Tp>

for _Dp . _Tp here is the _Tp from the primary template , not from the specialization.

In the specialization, the argument given for the primary template's _Tp is _Tp[] , where the latter _Tp is the specialization's one.

Therefore with eg unique_ptr<int[]> , the specialization is preferred with the specialization's _Tp equal to int , but the primary template's _Tp is int[] and so the default argument for _Dp , which is taken from the primary template, is default_delete<int[]> , not default_delete<int> .

Given unique_ptr<int[]> , the primary template is checked firstly, as the result _Tp is deduced as int[] , and _Dp would be default_delete<int[]> (from the default value.)

Then the specializations are checked. The specialization is defined as unique_ptr<_Tp[], _Dp> ; from the deduction result got above, it's replaced as unique_ptr<int[], default_delete<int[]>> , then the template parameter _Tp and _Dp of the specialization are deduced as int and default_delete<int[]> . (They're independent with the template parameters of the primary template.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM