В чем разница между std :: move и unique_ptr :: release? - PullRequest
0 голосов
/ 16 апреля 2020

Мне интересно, почему pstr2 не является нулевым в 4-й строке STDOUT. AFAIK, переезд и отпуск не имеют права собственности после звонка.

  auto pstr = make_unique<string>(5, '*');
  cout << (pstr ? *pstr : "pstr is empty") << endl;
  auto pstr2(pstr.release());
  cout << (pstr ? *pstr : "pstr is empty") << endl;
  cout << (pstr2 ? *pstr2 : "pstr2 is empty") << endl;
  auto pstr3(move(pstr2));
  cout << (pstr2 ? *pstr2 : "pstr2 is empty") << endl;
  cout << (pstr3 ? *pstr3 : "pstr3 is empty") << endl;

Выход

*****
pstr is empty
*****
***** <-- my curious part.
*****

Ответы [ 3 ]

2 голосов
/ 16 апреля 2020

Я думаю, вы предполагаете, что pstr.release() возвращает std::unique_ptr, тогда как в написанном коде возвращается std::string *. Поскольку это нельзя перенести, это объясняет результаты, которые вы получаете.

Если вы измените:

auto pstr2(pstr.release());

на:

auto pstr2 = unique_ptr<string>(pstr.release());

, то вы получите результаты, которые вы ожидаем.

Живая демоверсия

2 голосов
/ 16 апреля 2020

Когда вы объявляете переменную как auto для ее типа, ее фактический тип определяется из любого значения, присвоенного переменной во время ее инициализации.

Тип pstr выводится как unique_ptr<string>, потому что это то, что make_unique<string>(5, '*') возвращает.

auto pstr2(pstr.release()); не делает то, что вы думаете, что оно делает. release() не возвращает unique_ptr<string>, как вы ожидаете. Он возвращает необработанный указатель string*, который удерживался pstr. Таким образом, тип pstr2 выводится как string*, а не как unique_ptr<string> (а поскольку pstr отказался от владения указателем string*, вам нужно явно вызвать delete pstr2;, когда вы закончите или же объект string будет пропущен).

Аналогично auto pstr3(move(pstr2));. Поскольку pstr2 является необработанным string*, а std::move() является просто копией необработанного указателя, тип pstr3 также выводится как string*, а не unique_ptr<string>. pstr2 и pstr3 указывают на один и тот же объект string в памяти, поэтому ни один из них не является нулевым, и оба выводят одинаковые данные на консоль.

Если вы измените тип pstr2 для явной замены auto на unique_ptr<string> (или decltype(pstr)), тогда вы получите ожидаемое поведение, например:

auto pstr = make_unique<string>(5, '*');
cout << (pstr ? *pstr : "pstr is empty") << endl;
unique_ptr<string> pstr2(pstr.release());
// or: decltype(pstr) pstr2(pstr.release());
cout << (pstr ? *pstr : "pstr is empty") << endl;
cout << (pstr2 ? *pstr2 : "pstr2 is empty") << endl;
auto pstr3(move(pstr2));
// or: decltype(pstr2) pstr3(move(pstr2));
cout << (pstr2 ? *pstr2 : "pstr2 is empty") << endl;
cout << (pstr3 ? *pstr3 : "pstr3 is empty") << endl;

Output

*****
pstr is empty
*****
pstr2 is empty
*****

Демоверсия

1 голос
/ 16 апреля 2020

Поскольку pstr.release () возвращает необработанный указатель, то pstr2 и pstr3 выводятся как необработанные указатели.

После компиляции они похожи на

unique_ptr<string> pstr = make_unique<string>(5, '*');
string* pstr2(pstr.release());
string* pstr3(move(pstr2));
...