2

I initialized an unique_ptr with an Object. As i want to pass a reference of it to a function and don't let the function to change the object contents, I have to pass unique_ptr<const MyObject>& to it. But gcc 5.4 doesn't let me to initialize unique_ptr<const MyObject>& from uinque_ptr<MyObject>.

Example Code:

class Foo{public 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:

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

So is there any reasonable way to do it?

7
  • You could provide the raw pointer from foo.get() as const Foo* for the client. Commented Mar 5, 2017 at 8:18
  • 2
    If a function isn't allowed to modify the object anyway, what's the reason behind passing a smart pointer instead of a regular pointer? Commented Mar 5, 2017 at 8:18
  • @πάνταῥεῖ If i provide regular const pointer to user, he can delete it. Commented Mar 5, 2017 at 8:31
  • 1
    @hamed1soleimani With enough determination, a user can delete a pointer from inside unique_ptr, too, so it's not a new problem. Commented Mar 5, 2017 at 8:49
  • 1
    @hamed1soleimani: C++ guards against Murphy, not against Machiavelli. Commented Mar 5, 2017 at 13:14

2 Answers 2

7

There are two issues:

  • How to constify the referent of a unique_ptr.
  • How to pass a non-owning pointer to a function.

The reasonable way to pass a non-owning pointer is to pass a raw pointer:

some_function( my_unique_ptr.get() );

Or if it can't be null then you can dereference the pointer and pass a reference,

some_function( *my_unique_ptr )

This means that the constification is pretty much irrelevant to the main issue, but still, here's how to do that also:

unique_ptr<Foo>         p{ new Foo() };
unique_ptr<const Foo>   q{ move( p ) };    // Moves ownership!
Sign up to request clarification or add additional context in comments.

4 Comments

If i pass the pointer user could delete it. Event it's const pointer. Also i don't want to release ownership of the object by moving it. Only i want to pass a reference of the unique_ptr
It it can't be null then you can dereference the pointer and pass a reference, some_function( *my_unique_ptr ). If it can be null, the general case, then just pass the raw pointer. By convention, a raw pointer does not carry ownership: it would be wrong of the called function to delete it.
Amended the answer with that advice.
@cheers-and-hth-alf Yeah, I don't want to pass raw pointer of it, because user could delete it. But as i'm sure that it's not empty i could dereference it and pass cosnt Foo&.
2

A valid answer has already been posted.

I just want to provide some additional ideas for the case that the pointer could be empty.

Idea 1: Wrap the pointer into a std::shared_ptr with empty deleter:

#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

Idea 2: Use boost::optional to pass a reference but still allow it to be empty. Unfortunately this doesn't work with std::optional because std::optional doesn't allow reference arguments.

#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

Conclusion:

I would prefer boost::optional because it better expresses the intention.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.