Неподвижный уникальный указатель С++ 17
Я наткнулся на этот ответ " Запретить перемещение unique_ptr С++ 11". Тем не менее, при тестировании его на компиляторе в сети, это работает с С++ 11 (ошибка компилятора std::move
), но с С++ 17, я вижу, что std::move
ниже успешно. Разве компилятор не должен выдавать ошибку в этой строке? Также, если некоторая семантика изменилась в С++ 17, каков правильный способ создания неизменяемого unique_ptr в С++ 17 и далее.
template <typename T>
using scoped_ptr = const std::unique_ptr<T>;
int main()
{
auto p = scoped_ptr<int>(new int(5));
auto p2 = std::move(p); // should be error?
std::cout << *p2 << std::endl; // 5
return 0;
}
Вы можете попробовать это онлайн здесь.
Ответы
Ответ 1
p
не const
. Смотрите здесь, чтобы это провалилось так, как вы ожидаете.
auto
выводит как template<class T>void foo(T)
. T
никогда не выводится как const
, как и auto p=
.
Между тем, auto p =
строка auto p =
работает, потому что вы скомпилировали ее в режиме c++17. В c++11 он не компилируется. Это потому, что как значения отличаются в 17; некоторые называют разницу гарантированной.
Если вы хотите неподвижный уникальный ptr:
template<class T, class D>
struct immobile_ptr:private std::unique_ptr<T, D>{
using unique_ptr<T>::operator*;
using unique_ptr<T>::operator->;
using unique_ptr<T>::get;
using unique_ptr<T>::operator bool;
// etc
// manually forward some ctors, as using grabs some move ctors in this case
};
template<class T, class...Args>
immobile_ptr<T> make_immobile_ptr(Args&&...args); // todo
альтернатива может заключаться в том, чтобы взять уникальный ptr с неподвижным разрушителем.
template<class X>
struct nomove_destroy:std::destroy<T>{
nomove_destroy(nomove_destroy&&)=delete;
nomove_destroy()=default;
nomove_destroy& operator=(nomove_destroy&&)=delete;
};
template<class T>
using nomove_ptr=std::unique_ptr<T,nomove_destroy<T>>;
Но я не уверен, что это сработает.
Ответ 2
Следует отметить, что p
объявлен как нереференсного типа, const
часть аргумента scoped_ptr<int>(new int(5))
игнорируются в типе выводе. Тогда результатом вывода типа для p
будет std::unique_ptr<int>
, а не const std::unique_ptr<int>
(т. scoped_ptr<int>
как вы и ожидали).
То, что вы хотите, может быть
auto& p = scoped_ptr<int>(new int(5)); // p is of type const std::unique_ptr<int>& now
Ответ 3
Добро пожаловать в мир дедукции типов в C++. Пытаться
auto & p = scoped_ptr<int>(new int(5));
или же
auto && p = scoped_ptr<int>(new int(5));
вместо. Эта лекция может быть полезна: https://www.youtube.com/watch?v=wQxj20X-tIU