Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::unique_ptr constexpr constructors

Tags:

c++

c++11

c++14

As shown here, std::unique_ptr has two constexpr constructors for null pointers:

constexpr unique_ptr();
constexpr unique_ptr( nullptr_t );

I have two questions for these two constructors:

  1. Why do we need two? Can't we just declare one as:

    constexpr unique_ptr( nullptr_t = nullptr );
    
  2. Is the constexpr really useful? I tried doing this in my code but it didn't compile (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
    
like image 741
Zizheng Tai Avatar asked Jul 23 '16 06:07

Zizheng Tai


People also ask

Can unique_ptr be assigned?

It can be assigned: class owner { std::unique_ptr<someObject> owned; public: owner() { owned=std::unique_ptr<someObject>(new someObject()); } };

How do you transfer ownership of a pointer that is exclusively owned?

In C++11 we can transfer the ownership of an object to another unique_ptr using std::move() . After the ownership transfer, the smart pointer that ceded the ownership becomes null and get() returns nullptr.

What is std :: unique_ptr?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.


1 Answers

For (1), consider that it ensures that both the no-arg constructor unique_ptr() and null-pointer constructor unique_ptr(nullptr_t) have the same compile-time guarantees, i.e. both are constexpr. We can see the difference in §20.8.1.2:

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

Why the two were not combined into a single constructor with a default value is likely historical contingency.

With regards to (2), why we should care about constexpr despite having a non-trivial destructor, consider the answer given here:

constexpr constructors can be used for constant initialization, which, as a form of static initialization, is guaranteed to happen before any dynamic initialization takes place.

For example, given a global std::mutex:

std::mutex mutex;

In a conforming implementation (read: not MSVC), constructors of other objects can safely lock and unlock mutex, becuase std::mutex's constructor is constexpr.

like image 182
obataku Avatar answered Oct 19 '22 02:10

obataku