Может ли unique_ptr принимать значение nullptr?

Является ли этот фрагмент кода действительным? :

unique_ptr<A> p(new A());
p = nullptr;

То есть могу ли я присвоить nullptr unique_ptr ? или не получится?

Я попробовал это с компилятором g++, и это сработало, но как насчет других компиляторов?


person Zhen    schedule 25.02.2013    source источник


Ответы (2)


Это сработает.

Из параграфов 20.7.1.2.3/8-9 стандарта С++ 11 о шаблоне класса unique_ptr<>:

unique_ptr& operator=(nullptr_t) noexcept;

Эффекты: reset().

Постусловие: get() == nullptr

Это означает, что определение шаблона класса unique_ptr<> включает перегрузку operator =, которая принимает значение типа nullptr_t (например, nullptr) в качестве правой части; абзац также указывает, что назначение nullptr на unique_ptr эквивалентно сбросу unique_ptr.

Таким образом, после этого присваивания ваш объект A будет уничтожен.

person Andy Prowl    schedule 25.02.2013
comment
Понимаю. Кстати, только nullptr имеет nullptr_t, так это делается, не так ли? - person Zhen; 25.02.2013
comment
@Zhen: в стандарте это не указано. Вы можете создать переменную типа nullptr_t, но я сомневаюсь, что вам когда-либо понадобится это делать. - person Andy Prowl; 25.02.2013

Более распространенный случай:

#include <iostream>
#include <string>
#include <memory>

class A {
public:
    A() {std::cout << "A::A()" << std::endl;}
    ~A() {std::cout << "A::~A()" << std::endl;}
};

class B {
public:
    std::unique_ptr<A> pA;
    B() {std::cout << "B::B()" << std::endl;}
    ~B() { std::cout << "B::~B()" << std::endl;}
};

int main()
{
    std::unique_ptr<A> p1(new A());

    B b;
    b.pA = std::move(p1);
}

Выход:

A::A()
B::B()
B::~B()
A::~A()

Этот пример кода может быть неинтуитивным:

#include <iostream>
#include <string>
#include <memory>

class A {
public:
    A() {std::cout << "A::A()" << std::endl;}
    ~A() {std::cout << "A::~A()" << std::endl;}
};

class B {
public:
    std::unique_ptr<A> pA;
    B() {std::cout << "B::B()" << std::endl;}
    ~B() 
    {
        if (pA)
        {
            std::cout << "pA not nullptr!" << std::endl;
            pA = nullptr; // Will call A::~A()
        }
        std::cout << "B::~B()" << std::endl;
    }
};

int main()
{
    std::unique_ptr<A> p1(new A());

    B b;
    b.pA = std::move(p1);
}

Выход:

A::A()
B::B()
pA not nullptr!
A::~A()
B::~B()
person mrgloom    schedule 16.07.2019