Конструкторы std:: unique_ptr constexpr

Как показано здесь, std::unique_ptr имеет два конструктора constexpr для нулевых указателей:

constexpr unique_ptr();
constexpr unique_ptr( nullptr_t );

У меня есть два вопроса для этих двух конструкторов:

  • Зачем нам нужны два? Разве мы не можем объявить его как:

    constexpr unique_ptr( nullptr_t = nullptr );
    
  • Действительно ли constexpr полезен? Я пробовал делать это в своем коде, но он не компилировался (g++ 6.1.0, -std=c++14):

    constexpr std::unique_ptr<int> p;
    // error: the type 'const std::unique_ptr<int>' of constexpr variable 'p'
    // is not literal because 'std::unique_ptr<int>' has a non-trivial destructor
    

Ответы

Ответ 1

В отношении (1) учтите, что он гарантирует, что и конструктор no-arg unique_ptr(), и конструктор с нулевым указателем unique_ptr(nullptr_t) имеют одинаковые гарантии времени компиляции, т.е. оба значения constexpr. Мы можем видеть разницу в §20.8.1.2:

constexpr unique_ptr() noexcept;
explicit unique_ptr(pointer p) noexcept;
...
constexpr unique_ptr(nullptr_t) noexcept
: unique_ptr() { }

Почему два не были объединены в один конструктор со значением по умолчанию, вероятно, являются историческими обстоятельствами.

Что касается (2), почему мы должны заботиться о constexpr, несмотря на отсутствие нетривиального деструктора, рассмотрим ответ, приведенный здесь:

Конструкторы

constexpr могут использоваться для постоянной инициализации, которая, как форма статической инициализации, гарантирована, прежде чем произойдет любая динамическая инициализация.

Например, с учетом глобального std::mutex:

std::mutex mutex;

В соответствующей реализации (read: not MSVC) конструкторы других объектов могут безопасно блокировать и разблокировать конструктор mutex, becuase std::mutex constexpr.

Ответ 2

Что касается Q1, конструктор nullptr_t был добавлен позже в N2435, после первоначального предложения (N1586).

Добавление простой перегрузки, которая может быть указана в одной строке, намного чище, чем попытка быть умной, тем более что [member.functions] уже позволяет реализации использовать "умную" версию, если они этого хотят.