4

The following code does not compile:

#include <iostream>
#include <memory>

class A
{
public:
    A( )
        : m_i( new int )
    { }

    std::shared_ptr< const int >&
    get( )
    {
        return m_i; // <-- invalid initialization of reference of type
                    //     'std::shared_ptr<const int>&' from 
                    //     expression of type 'std::shared_ptr<int>'
    }

private:
    std::shared_ptr< int > m_i;
};


int main( )
{
    A a;
    auto& i = a.get( );

    std::cout << *i << std::endl;
    return 0;
}

How is it possible to cast from a shared pointer to a shared pointer to constant object? static_cast also fails.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
nyarlathotep108
  • 5,275
  • 2
  • 26
  • 64
  • 3
    I think it is almost never a good idea to return a reference to a smart pointer. Either the caller needs a smart pointer in which case it is safer to return a smart pointer by value (see Bathsheba's answer) to avoid dangling references. Or the caller doesn't need a smart pointer in which case it is simpler to return a pointer or reference directly (see my answer). – Chris Drew Jul 10 '17 at 10:47
  • Bad code and bad question. You cannot return a reference to a temporary. Please explain your constraints. – curiousguy Jul 10 '17 at 10:50
  • The correct term here is **conversion**, not **cast**. A cast is something you write in your code to tell the compiler that you want it to do a conversion. – Pete Becker Jul 10 '17 at 13:02

2 Answers2

8

Change your get to

std::shared_ptr<const int> get( )

which will remove what is essentially a dangling reference, and compilation will succeed.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • That is true, but I need the same reference counted, just pointing to a constant type. With your solution, I am going to have two smart pointers in the end. – nyarlathotep108 Jul 10 '17 at 10:04
  • Well you're out of luck then. (Although I do invite folk to downvote this if I've simply given up through lack of ability!) You can't bind to a reference unless the types match exactly. – Bathsheba Jul 10 '17 at 10:05
  • 7
    Either I misunderstand nyarlathotep108's comment or I missunderstand Bathsheba's answer. You do have two smart pointers in the end but they point to the same memory and share the same reference count, isn't that what you want? – Chris Drew Jul 10 '17 at 10:15
  • 1
    @nyarlathotep108 yes you get 2 pointers in the end. If you never have more than 1 pointer to the object, then there is absolutely no need for `shared_ptr`. That's the whole purpose of `shared_ptr` : having multiple pointers sharing ownership of a resource. – bolov Jul 10 '17 at 10:34
  • @nyarlathotep108 have a look at [shared_ptr::shared_ptr (9)](http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr) – Caleth Jul 10 '17 at 10:39
7

If the caller of A::get only wants to observe m_i and doesn't want to obtain shared ownership then I would just return a pointer-to-const:

const int* get( ) { return m_i.get(); }

Holding a reference to a smart-pointer is no safer than a raw pointer. If the owner of the smart pointer goes out of scope you will have a dangling reference to a smart pointer.

Chris Drew
  • 14,926
  • 3
  • 34
  • 54