不可移动的 C++17 唯一指针

Posted

技术标签:

【中文标题】不可移动的 C++17 唯一指针【英文标题】:Non-Movable C++17 Unique Pointer 【发布时间】:2018-11-24 06:08:17 【问题描述】:

我遇到了这个答案Prevent moving of a unique_ptr C++11。但是,在在线编译器上试用它时,这适用于 C++11(std::move 编译器错误),但对于 C++17,我看到下面的 std::move 是成功的。编译器不应该在该行抛出错误吗?此外,如果 C++17 中的某些语义发生了变化,那么在 C++17 及更高版本中创建不可移动的 unique_ptr 的正确方法是什么。

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;

您可以在线试用here。

【问题讨论】:

【参考方案1】:

p 不是const。请参阅 here 以了解它是否会按您预期的方式失败。

auto 的推论类似于template&lt;class T&gt;void foo(T)T 永远不会被推导出为 constauto p= 也不是。

同时,auto p = 行有效,因为您在 c++17 模式下编译了它。在c++11it does not compile。这是因为 prvalues 在 17 中有何不同;有些人称差异为保证省略。

如果你想要一个固定的唯一指针:

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>>;

但我不确定这是否可行。

【讨论】:

如果我正确阅读了overload #6,那么删除技巧应该会起作用。整洁!【参考方案2】:

注意p 被声明为非引用类型,参数scoped_ptr&lt;int&gt;(new int(5))const 部分在类型推导中被忽略。那么p的类型推导结果是std::unique_ptr&lt;int&gt;,而不是const std::unique_ptr&lt;int&gt;(即你所期望的scoped_ptr&lt;int&gt;)。

你想要的可能是

auto& p = scoped_ptr<int>(new int(5)); // p is of type const std::unique_ptr<int>& now

【讨论】:

auto&amp; 不会使其成为非引用类型const std::unique_ptr&lt;int&gt;,是吗? @ShadowRanger 你的意思是const std::unique_ptr&lt;int&gt;&amp; ? 以这种方式跨版本工作coliru.stacked-crooked.com/a/aef0f48df5604e38【参考方案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

【讨论】:

感谢您的建议讲座 - 我想我需要再看一遍并阅读 Modern Effective C++ 中的相关材料 :)

以上是关于不可移动的 C++17 唯一指针的主要内容,如果未能解决你的问题,请参考以下文章

环形缓冲区

在可移动和不可复制的类上使用移动和交换习语是不是有意义

为啥 c++ 线程是可移动的但不可复制的?

cpp►C++11右值引用移动语义移动构造函数移动赋值运算符

cpp►C++11右值引用移动语义移动构造函数移动赋值运算符

Initializer-list-构造一个不可复制(但可移动)对象的向量