Home > Back-end >  Is there a difference between a copy constructor with an argument type of `const T &` and of type `c
Is there a difference between a copy constructor with an argument type of `const T &` and of type `c

Time:09-17

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.

  • Related