Есть ли законный способ перейти с gsl::not_null‹T›?

Библиотека поддержки рекомендаций представила not_null<T>, целью которого является применение инварианта к типам, подобным указателям, преднамеренно к умным указателям. . Однако известно, что not_null<unique_ptr<T>> не работает.

Насколько я понимаю, причина в том, что unique_ptr<T> не является копируемым, а not_null<T> не имеет конструктора, который перемещался бы из его T. not_null<T> также не является конструируемым по умолчанию, потому что это нарушило бы его инвариант. Даже если бы мы могли построить not_null<unique_ptr<T>>, было бы невозможно осмысленно добраться до unique_ptr внутри, потому что мы не могли скопировать unique_ptr, и его перемещение оставило бы not_null<T> с нулевым значением. Похоже на идеальную ловушку.

Я утверждал, что мы можем законно отказаться от объекта not_null<T> в определенном контексте: непосредственно перед тем, как он выйдет за рамки. Другими словами, перемещение из него должно быть последним доступом перед уничтожением. Таким образом, объект с нарушенным инвариантом не будет виден остальной части программы. (Это можно было бы наблюдать только для собственного кода not_null.)

В следующих примерах предположим, что мы можем перейти от not_null<T>.

not_null<unique_ptr<int>> f()
{
    return make_unique<int>(1);
}

void g(not_null<unique_ptr<int>> p)
{
    ...
}

void h()
{
    auto p = f();
    g(make_unique<int>(2));
}
  1. Верно ли мое предположение, что состояние not_null<unique_ptr<int>>, возвращенное из f(), не могло утечь после перехода от него (только для примера)?

  2. Верно ли мое предположение, что состояние not_null<unique_ptr<int>>, переданное в g(), не могло утечь после перехода от него (просто для примера)?

  3. Можно ли разрешить этот особый вид перемещения, запретив общий случай перемещения в C++ 14/17?


person kkeri    schedule 15.02.2016    source источник
comment
Относительно 3: см. github.com/microsoft/GSL/pull/842, особенно комментарий от hsutter. Для общего решения конструкция перемещения в сочетании с std::move является проблемой, сравните auto p=f(); auto q=std::move(p);, где после перемещения p не может содержать никакого значимого значения, которое не нарушает инвариант класса, отличный от нуля (нет допустимого значения по умолчанию для установки p).   -  person Werner Henze    schedule 28.02.2020


Ответы (1)


1 и 2: Игнорирование того факта, что elision сделает вопрос спорным для любого компилятора, который стоит использовать, да. Также игнорируется тот факт, что unique_ptr не может "утекать".

3: No.

Это было предметом обсуждения в списке рассылки предложений ISO C++. Общая концепция заключается в «деструктивном перемещении», когда действие перемещения от объекта и его уничтожение выполняются в одном и том же вызове. Но это должно быть особенностью языка; в С++ 14 нет способа определить, вызывается ли конструктор/присваивание перемещения таким образом, что данный объект определенно собирается быть уничтоженным.

person Nicol Bolas    schedule 15.02.2016
comment
Исключение копирования действительно сложно, так как это единственная разрешенная форма оптимизации, которая может изменить наблюдаемые побочные эффекты (от cppreference.com). Спасибо, что упомянули об этом. Под утечкой я имел в виду утечку информации, а не памяти, но ваш комментарий в любом случае актуален. Наконец, я не знал о дебатах, но это было то, чего я ожидал. - person kkeri; 17.02.2016