8

I'm going to omit quite bit of code because these are some rather large objects, and my question really just concerns the operation of std::make_shared . I have an object in namespace SYNC called called D3D11Shader. This has a static function called,

SYNC::D3D11Shader * SYNC::D3D11Shader::CreateInstance(const std::string & s)

which will take a string index and return a pointer to an instance of a shader that is derived from SYNC::D3D11Shader. At one point i started using smart pointers to automate deallocation of these within the vector that held all these shaders. However, when i go to do this,

 std::shared_ptr<SYNC::D3D11Shader> shaderPtr;
 // ... verification of index and other initialization happens here
 // so i am unable to initialize it in it's constructor
 shaderPtr = std::make_shared<SYNC::D3D11Shader>(SYNC::D3D11Shader::CreateShader(shaderName));

the compiler errors saying that i am trying to instanciate an instance of D3D11Shader in this line which is an abstract class. I thought all make_shared did was return an instance of std::shared_ptr. The CreateInstance function never tries to make an instance of this class, just objects that derive and implement it. I was not getting this error before using this function and the smart pointers. Does anyone know what's going on here?

FatalCatharsis
  • 3,407
  • 5
  • 44
  • 74
  • 2
    Check the documentation of make_shared http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared or http://msdn.microsoft.com/en-us/library/ee410595.aspx – R. Martinho Fernandes Nov 09 '12 at 16:06
  • Well shoot, key phrase in the defintion being, "Constructs an object." is there anyway to simply set a shared_ptr to a pointer after initialization? – FatalCatharsis Nov 09 '12 at 16:12
  • Use shared_ptr's constructor directly `shared_ptr ptr(your_pointer_here);`, or `ptr.reset(your_pointer_here);` if you have an existing one. – R. Martinho Fernandes Nov 09 '12 at 16:13
  • 1
    I think the best solution would be to rewrite the interface of `CreateInstance` to return a shared pointer. Then you can use `make_shared` inside *that* code. – Kerrek SB Nov 09 '12 at 16:21

2 Answers2

16

If you can't use the constructor of shared_ptr, use its reset member function to give it ownership of a new object:

std::shared_ptr<SYNC::D3D11Shader> shaderPtr;
shaderPtr.reset(SYNC::D3D11Shader::CreateShader(shaderName));

The reason make_shared<T> is not appropriate for this situation is because it constructs a new T, forwarding its arguments to its constructor. You've already constructed an object, though, so you just want to give ownership to your shared pointer.

I highly recommend not returning a raw pointer from CreateShader though. You're relying on the caller of CreateShader to know to either wrap it up in a smart pointer or call delete on it. You'd be better off returning a unique_ptr directly, to pass ownership to the client, and then they can make a shared_ptr out of it if they like. See the following:

std::unique_ptr<SYNC::D3D11Shader> uniquePtr(SYNC::D3D11Shader::CreateShader(shaderName));
// If you want a shared_ptr:
std::shared_ptr<SYNC::D3D11Shader> sharedPtr(std::move(uniquePtr));

Or simply:

std::shared_ptr<SYNC::D3D11Shader> sharedPtr = SYNC::D3D11Shader::CreateShader(shaderName);

If you're going to use smart pointers, use them. :)

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
2

Easy enough:

shaderPtr.reset(SYNC::D3D11Shader::CreateShader(shaderName));

You can see the different variants of the reset member function here.

rodrigo
  • 94,151
  • 12
  • 143
  • 190