从 unique_ptr 初始化 unique_ptr 常量引用

Posted

技术标签:

【中文标题】从 unique_ptr 初始化 unique_ptr 常量引用【英文标题】:initialize unique_ptr const reference from a unique_ptr 【发布时间】:2017-03-05 08:08:15 【问题描述】:

我用一个对象初始化了一个 unique_ptr。因为我想将它的引用传递给函数并且不让函数更改对象内容,所以我必须将 unique_ptr<const MyObject>& 传递给它。但是 gcc 5.4 不允许我从 uinque_ptr<MyObject> 初始化 unique_ptr<const MyObject>&

示例代码:

class Foopublic int x;;
unique_ptr<Foo> foo(new Foo());
foo->x = 5;

// User shouldn't be able to touch bar contents.
unique_ptr<const Foo>& bar = foo;

C++ 错误:

error: invalid initialization of reference of type ‘std::unique_ptr<const Foo>&’ from expression of type ‘std::unique_ptr<Foo>’

那么有什么合理的方法可以做到吗?

【问题讨论】:

您可以将来自foo.get() 的原始指针作为const Foo* 提供给客户端。 如果一个函数无论如何都不允许修改对象,那么传递智能指针而不是常规指针的原因是什么? @πάνταῥεῖ 如果我向用户提供常规 const 指针,他可以删除它。 @hamed1soleimani 如果有足够的决心,用户也可以从unique_ptr 中删除指针,所以这不是一个新问题。 @hamed1soleimani:C++ 防范墨菲,而不是马基雅维利。 【参考方案1】:

有两个问题:

如何constifyunique_ptr 的引用对象。 如何将非拥有指针传递给函数。

传递非拥有指针的合理方法是传递原始指针:

some_function( my_unique_ptr.get() );

或者如果它不能为空,那么你可以取消引用指针并传递一个引用,

some_function( *my_unique_ptr )

这意味着约束与主要问题几乎无关,但是,这也是如何做到这一点的:

unique_ptr<Foo>         p new Foo() ;
unique_ptr<const Foo>   q move( p ) ;    // Moves ownership!

【讨论】:

如果我通过指针用户可以删除它。事件它是 const 指针。我也不想通过移动它来释放对象的所有权。只有我想传递 unique_ptr 的引用 它不能为空,那么您可以取消引用指针并传递引用,some_function( *my_unique_ptr )。如果它可以为空,一般情况下,那么只需传递原始指针。按照惯例,原始指针不携带所有权:被调用的函数删除它是错误的。 用该建议修改了答案。 @cheers-and-hth-alf 是的,我不想传递它的原始指针,因为用户可以删除它。但我确信它不是空的,我可以取消引用它并传递cosnt Foo&amp;【参考方案2】:

valid answer 已发布。

我只是想为指针可能为空的情况提供一些额外的想法。

想法 1: 将指针包装成带有空删除器的 std::shared_ptr

#include <iostream>
#include <memory>

struct Foo int x; ;

void Fun( std::shared_ptr<const Foo> p ) 
    if( p )     
        std::cout << "p.x: " << p->x << std::endl;
    //won't compile:
    //delete p;


int main()
    std::unique_ptr<Foo> foo(new Foo());
    foo->x = 5;

    std::shared_ptr<const Foo> bar( foo.get(), []( const Foo* ) );
    Fun( bar );

    return 0;

Live Demo

想法 2: 使用 boost::optional 传递引用,但仍然允许它为空。不幸的是,这不适用于std::optional,因为std::optional 不允许引用参数。

#include <iostream>
#include <memory>
#include <boost/optional.hpp>

struct Foo int x; ;

using OptionalFooConstRef = boost::optional<Foo const&>;

void Fun( OptionalFooConstRef p )
    if( p )
        std::cout << "p.x: " << p->x << std::endl;
    else
        std::cout << "no foo\n";
    //won't compile:
    //delete p;


int main()
    std::unique_ptr<Foo> foo(new Foo());
    foo->x = 5;

    Fun( foo ? OptionalFooConstRef( *foo ) : boost::none );

    std::unique_ptr<Foo> nofoo;
    Fun( nofoo ? OptionalFooConstRef( *nofoo ) : boost::none );

    return 0;

Live Demo

结论:

我更喜欢boost::optional,因为它更好地表达了意图。

【讨论】:

以上是关于从 unique_ptr 初始化 unique_ptr 常量引用的主要内容,如果未能解决你的问题,请参考以下文章

智能指针之unique_ptr

[C++11]独占的智能指针unique_ptr的初始化和使用

在类中初始化 unique_ptr

如何初始化一个unique_ptr

如何在构造函数中使用删除器初始化 std::unique_ptr?

vector<unique_ptr> 的初始化失败并出现复制错误