EddieV223
EddieV223

Reputation: 5303

Learning c++11 smart pointer, it won't let me use implicit conversion like a pointer can?

I have a ISceneNode interface and from that a SceneNode base class. From the SceneNode class derive MeshNode, AnimNode, LightNode, CameraNode, ect...

Now I have an actor class that through a method takes in a shared_ptr and stores it in a field.

What I'd like to be able to do is send in any std::shared_ptr or other derived classes into the function that takes in a shared_ptr .

With bare pointers this would be an implicit conversion.

The solution that I came up with was to write a overload for each of the derives and then cast it within the method using dynamic_pointer_cast . That's just nasty there should be a better way.

Is there a way to get implicit casting, or a better way I don't know of to handle this? What's the proper way to handle this?

void SomeFunc()
{
    std::shared_ptr<MeshNode> pMeshNode( new MeshNode() );
    gActor.SetNode( pMeshNode );  // won't compile.

    // or do i have to do it like this
    gActor.SetNode( std::dynamic_pointer_cast<ISceneNode> (pMeshNode) );
}

void Actor::SetNode( std::shared_ptr<ISceneNode> pNode )
{
    mpNode = pNode;
}

// or do I have to do it like this?  Making an over load for each derived.
void Actor::SetNode( std::shared_ptr<MeshNode> pMeshNode )
{
    mpNode = std::dynamic_pointer_cast<ISceneNode> (pMeshNode);
}

Upvotes: 0

Views: 382

Answers (2)

Mateusz Pusz
Mateusz Pusz

Reputation: 1393

I bet you are using VS2010? I found some problems with smart pointers support there? On a compiler with better C++11 support (eg. VS2012, gcc, clang) it should compile fine. However I would suggest you some extensions:

class Actor {
  std::shared_ptr<ISceneNode> mpNode;
public:
  void SetNode(std::shared_ptr<ISceneNode> pNode)
  { mpNode = std::move(pNode); }
};

void SomeFunc()
{
  gActor.SetNode(std::make_shared<MeshNode>());
}

It is always better to allocate std::shared_ptr with std::make_shared<T>() which saves you one dynamic allocation and even up to the half of shared state memory overhead. You should also either pass std::shared_ptr as a reference to a function or at least move it to a new value like I did. You could also consider using std::unique_ptr which makes it even more effective (no shared state memory overhead and thread safe reference counting) and makes the design better (clear ownership). You can use in a very similar way:

class Actor {
  std::unique_ptr<ISceneNode> mpNode;
public:
  void SetNode(std::unique_ptr<ISceneNode> pNode)
  { mpNode = std::move(pNode); }
};

void SomeFunc()
{
  gActor.SetNode(std::unique_ptr<MeshNode>(new MeshNode));
}

Upvotes: 2

moswald
moswald

Reputation: 11677

You claim it won't compile, but the following test compiles and runs for me (VS2012, Clang, G++). You should post the error you're getting, as it's most likely something else.

#include <memory>

struct IBase {};

struct Derived : IBase {};

void Foo(std::shared_ptr<IBase> p) {}

int main()
{
    std::shared_ptr<Derived> d;
    Foo(d);
}

Upvotes: 4

Related Questions