njensen
njensen

Reputation: 53

Create aliases to boost::shared_ptr via reference

I have a small segment of code that I need to optimize. Thread 'A' has created a boost shared_ptr to a heap object. Thread 'A' writes the shared_ptr to a thread safe queue. Thread 'B' reads the shared_ptr, uses it, and then destroys it.

Intense profiling/testing proves that the copying of the shared_ptr going in/out of the queue and adjusting reference counts is costly. Therefore, I would like to pass the shared ptr to the queue via reference. I would also like to use std::move to move the shared_ptr into the queue rather than construct a new shared_ptr, (I know this will invalidate the shared_ptr parameter which was passed to the queue).

Everything described works fine until I mix in a dash of polymorphism. I can't pass by ref a shared_ptr to a derived obj to a function expecting a shared_ptr to a base class. I have boiled this down to a very small snip that exposes the behavior that confuses me.

#include <boost/shared_ptr.hpp>

class Base
{
};

class Derived : public Base
{
};

int main()
{
  boost::shared_ptr<Derived> pDerived(new Derived());  // simple creation
  boost::shared_ptr<Derived> &alias1 = pDerived;       // works fine
  const boost::shared_ptr<Base> &alias2 = pDerived;    // also works fine
  boost::shared_ptr<Base> &alias3 = pDerived;          // compilation error

  //native pointers
  Derived *alias4 = pDerived.get();     //works
  const Base *alias5 = pDerived.get();  //works
  Base *alias6 = pDerived.get();        //works

  //native references
  Derived &alias7 = *pDerived;          // works
  const Base &alias8 = *pDerived;       // works
  Base &alias9 = *pDerived;             // works
}

I do not understand why the assignment to alias2 is perfectly fine, yet the assignment to alias3 yields a compiler error. Can someone please explain this? I need functionality like the alias3 example and can't make it work.

Upvotes: 3

Views: 182

Answers (1)

Eissa N.
Eissa N.

Reputation: 1725

This problem is not related to boost or smart pointers. It can happen with POD types too as shown in the following simple example:

int main() {
    int x = 0;
    const double &y = x; //fine
    double &z = x; //error!
    return 0;
}

The reason is that a temporary value (rvalue) can bind to a const& but it cannot bind to a &. What happens in double &z = x is that x and z are unrelated types, and x needs to be converted to a double and a temporary variable is created, which cannot bind to a &.

Upvotes: 0

Related Questions