As of C 11, std::allocator
defines three constructors that are roughly equivalent to those in the following class:
template<typename T>
class allocator {
public:
constexpr allocator() noexcept = default;
constexpr allocator(const allocator &other) noexcept = default;
template<typename U>
constexpr allocator(const allocator<U> &other) noexcept {};
};
The first is a default constructor, and the second is a copy constructor - pretty standard stuff. However, the third constructor confuses me quite a bit. It appears to technically be a specialization of the copy constructor? And if that is the case, would the second constructor ever even be called? Is = default
required? How does the compiler know to provide a default implementation for the third constructor?
CodePudding user response:
This template constructor
template<typename U>
constexpr allocator(const allocator<U> &other) noexcept {};
is not a copy constructor.
Copy constructor is a non-template member function of a class.
This template constructor is selected when std::is_same_v<T, U>
is equal to false.
CodePudding user response:
It [the third constructor] appears to technically be a specialization of the copy constructor?
It is not a copy constructor at all. It is actually a converting constructor instead.
would the second constructor ever even be called?
If an allocator<T>
object is used to construct another allocator<T>
object, then the second constructor will be used, yes. For example:
allocator<int> a1;
allocator<int> a2(a1);
But, if a different allocator<U>
object is used to construct an allocator<T>
object, where U
is not the same type as T
, then the third constructor will be used. For example:
allocator<short> a1;
allocator<int> a2(a1);
Is
= default
required?
Only if you want the compiler to auto-generate an implementation. Otherwise, you have to provide one yourself.
How does the compiler know to provide a default implementation for the third constructor?
Everything between {}
in a constructor's body is user-defined. If there is no {}
then you need to use = default
(or = delete
) instead.
In a non-deleted constructor, the compiler always default-initializes each class member, unless specified otherwise in the constructor's member initialization list - which the 3rd constructor does not have.