Деструктор вызывается перед функцией-членом при назначении unique_ptr ссылке

Я использую unique_ptr и получаю странные результаты. Это код:

class Sniffer
{
public:
    Sniffer()
    {
        cout << "Sniffer()" << endl;
        s = "String!";
    }

    void operator()()
    {
        cout << "operator()(): " << s << endl;
    }

    ~Sniffer()
    {
        cout << "~Sniffer()" << endl;
    }

private:
    string s;
};


int main()
{
    cout << "Begin scope!" << endl;

    {
        Sniffer& h = *std::unique_ptr<Sniffer>(new Sniffer());   // 1

        //std::unique_ptr<Sniffer> p(new Sniffer());             // 2
        //Sniffer& h = *p;                                       // 2

        h();
    }

    cout << "End scope!" << endl;
    return 0;
}

Я не понимаю, почему с кодом «1» деструктор вызывается перед оператором()(), а «Конец области!» вообще не печатается. Код не падает, он выполняется до последней строки, я получаю вывод:

Begin scope!
Sniffer()
~Sniffer()
operator()(): Press any key to continue . . .

С другой стороны код «2» ведет себя так, как ожидалось:

Begin scope!
Sniffer()
operator()(): String!
~Sniffer()
End scope!
Press any key to continue . . .

Причина, по которой я использую ссылку, заключается только в том, что я чувствовал, что h() более естественен, чем (*p)() или p->operator()(). Спасибо.


person Neuroentropy    schedule 27.03.2015    source источник


Ответы (4)


В этом заявлении

Sniffer& h = *std::unique_ptr<Sniffer>(new Sniffer());

создается временный объект типа std::unique_ptr<Sniffer>, который уничтожается в конце выполнения инструкции.

Таким образом, ссылка h недействительна в рамках блока кода.

В этом заявлении

std::unique_ptr<Sniffer> p(new Sniffer());             // 2

объект p создан и будет жить до конца блока кода. Итак, ссылка h

Sniffer& h = *p; 

будет действительным в этой области.

person Vlad from Moscow    schedule 27.03.2015

std::unique_pointer<Sniffer> является временным в вашем «1», поэтому уничтожается после завершения оператора. Его деструктор уничтожает объект Sniffer до того, как будет достигнута следующая инструкция (h();). h — это висячая ссылка, поэтому результат h() (т. е. h.operator()()) не определен.

В вашем случае «2» объект p продолжает существовать до конца содержащейся области, то есть после оператора h();

person Peter    schedule 27.03.2015

Это потому, что когда вы делаете

Sniffer& h = *std::unique_ptr<Sniffer>(new Sniffer());

объект std::unique_ptr, который вы создаете, является временным и уничтожается, оставляя вам ссылку на объект, которого больше не существует, и вы попадаете в страну неопределенное поведение.

Когда вы делаете

std::unique_ptr<Sniffer> p(new Sniffer());

вы создаете фактический невременный объект p, на который вы, конечно, можете ссылаться в течение его жизни.

person Some programmer dude    schedule 27.03.2015
comment
вы должны уточнить (это очевидно, я знаю, но все же), что динамический объект Sniffer, на который фактически указывает h, удаляется деструктором временного unique_ptr - person Guiroux; 27.03.2015

Строка 1 создает временный объект unique_ptr, который разыменовывается, и результатом этого является то, на что затем будет указывать ссылка h. Однако, поскольку объект unique_ptr является временным, его деструктор будет вызываться через точку с запятой (см. объект срок службы). Это также вызовет деструктор объекта Sniffer, на который указывает временный unique_ptr.

Код 2 действительно соответствует тому, как вы должны использовать unique_ptr. Или, что еще лучше, используйте make_unique C++14.

Вся цель unique_ptr заключается в том, что все, на что он указывает, будет автоматически уничтожено (или удалено специальным средством удаления), когда объект unique_ptr выйдет за пределы области видимости. В строке 1 он выходит за рамки еще до того, как вы использовали его содержимое. См. документацию:

std::unique_ptr — это интеллектуальный указатель, который сохраняет единоличное владение объектом через указатель и уничтожает этот объект, когда unique_ptr выходит за пределы области видимости.

person Lemming    schedule 27.03.2015