C++ - 返回const unique_ptr

26

我想知道为什么编译时出错:

const std::unique_ptr<int> get() { 
    return std::make_unique<int>(10);
}

int main() { 

    const std::unique_ptr<int> value = get();

    return EXIT_SUCCESS;
}

我收到以下错误:

main.cpp: In functionint main()’:
main.cpp:10:44: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
     const std::unique_ptr<int> value = get();

当我从get的签名中删除const时,它可以正确编译。

有没有办法返回一个常量 unique_ptr


有没有办法返回一个常量unique_ptr?

2
实际的 std::unique_ptr 对象应该是常量,还是其所指向的数据? - Some programmer dude
1
@MooingDuck 作为返回类型,这很奇怪。否则,pimpl 模式是一个常见的场景,其中有时会使用指向非 const 对象的 const unique_ptr。 总的来说,指向非 const 的 const 指针并不奇怪。如果让指针指向其他地方是错误的,但通过指针进行指向对象的改变是正确的,那么指向非 const 的 const 指针表达和强制执行了这一点。如果遵循在大多数情况下使大部分内容都是 const 的惯例,除非有理由不这样做,否则指向非 const 对象的 const 指针会相当经常出现。 - Eliah Kagan
1
@EliahKagan:在pimpl中使用const指针会使移动/交换变慢,但是总的来说,有些情况下使用const指针是有意义的。 - Mooing Duck
1
这是一个x/y问题,我不知道为什么它会得到如此高的投票。你说你想让unique_ptr是常量,尽管在添加像unique_ptr这样的不可复制类型之前,const返回值已经足够奇怪了,而且你没有解释为什么你认为你想要这种奇怪的东西。我觉得“为什么我不能做[没有明显理由的奇怪事情]”这样的问题是没有用的,否则我可以花一整天发明和发布它们。 - underscore_d
1
@MooingDuck,似乎有很多情况下使用const指针是一个好主意,至少如果我们重视const的正确性。当然,如果我们对函数签名有完全控制,应该使用引用。但是,我想到的一个简单的例子是,在持有指针的容器中对范围进行find_if等stdlib算法操作(reference_wrapper似乎不值得麻烦,而且本身也应该是const!)。如果在接收函数内部意外地改变了指针的可能性,并且发生了这种情况,那么结果将不会很好。 - underscore_d
显示剩余2条评论
1个回答

54

由于unique_ptr是常量,因此它只能被复制而不能被移动。并且不允许复制unique_ptr(否则它将不再是“unique”)。

如果指针所指向的数据应为常量,则应改用std::unique_ptr<const int>


2
简短说明:由于保证复制省略,OP的示例必须在C++17中编译。 - bogdan
@bogdan 你确定吗?我用-std=c++17在clang、gcc或msvc上编译不通过。 - patatahooligan
@bogdan std::unique_ptr 的复制构造函数和复制赋值运算符被标记为 delete,这意味着它不能用于任何类型的复制,即使可以省略复制。 - Some programmer dude
@patatahooligan 这些可能是编译器的旧版本吗?我使用较新的三个版本,Clang 5、GCC 7.3、MSVC 15.9,都能够成功编译。 - bogdan
1
@Someprogrammerdude 这是正确的,并且适用于C++17之前的任何情况。由于采用了P0135,规则在C++17中发生了变化。理由和示例在R0版本的论文中。基本上,从与目标类型相同的prvalue初始化不再被视为可以省略的临时复制/移动;它明确地基于prvalue创建目标对象;没有什么可以省略的了。 - bogdan
@bogdan 对不起,我犯了一个错误。我做了很多测试,把结果搞混了。OP的例子确实像你说的那样编译。不能编译的那个是返回本地const unique_ptr。尽管在实践中应该省略这个,但仍需要将类复制。 - patatahooligan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接