Jump to content
  • Advertisement
Sign in to follow this  
jdub

Help me fix this code using std::shared_ptr

This topic is 2149 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am starting to integrate smart pointers into my code.  However, I am still getting stuck up on exactly how to use them.  Here is the relevant code snippet:

bool DebugLayer::Init(
		DebugOptions options, 
		const std::shared_ptr<Renderer> &renderer, 
		const std::shared_ptr<const InputController> &inputController, 
		const std::shared_ptr<const Timer> &timer,
		const RECT& windowRect)
	{
		if(!inputController || !timer || !renderer || !inputController)
		{
			OutputDebugString("\nInvalid parameters passed to DebugLayer::Init()\n");
			return false;
		}

		this->debugOptions = options;
		this->renderer = std::make_shared<Renderer>(*renderer);
		this->inputController = std::make_shared<const InputController>(*inputController);
		this->timer = std::make_shared<const Timer>(*timer);

                ...
                ...

}

I am trying to pass const pointers to const objects into the function.  For some reason, when I try and set my own class instance shared_ptr objects to what I pass into Init() I get the following errors from <memory>:

 

Error 8 error C2440: '<function-style-cast>' : cannot convert from 'std::shared_ptr<_Ty>' to 'std::shared_ptr<_Ty>'
Error 9 error C2228: left of '.swap' must have class/struct/union
Error 10 error C2440: '<function-style-cast>' : cannot convert from 'std::shared_ptr<_Ty>' to 'std::shared_ptr<_Ty>'
 
 

Share this post


Link to post
Share on other sites
Advertisement
Is your intent to copy the data passed to init or to share it? If copy, then you should not pass in shared_ptr's; just pass the parameters by value. If share, then just assign the shared pointer member the passed object; no need for make_shared or dereferencing the pointers.

Share this post


Link to post
Share on other sites

make_shared allocates a new shared region from the pointer you pass in, i believe.

simply remove all the make_shared calls, and do a normal assignment and you're done.

Share this post


Link to post
Share on other sites

make_shared allocates a new shared region from the pointer you pass in, i believe.


No. std::make_shared passes whatever arguments it receives to the underlying class's constructor. The difference between
(1) someSharedPointer = std::shared_ptr<MyType>(new MyType(A, B, C, ...));
(2) someSharedPointer = std::make_shared<MyType>(A, B, C, ...);
is soley the fact, that there are two allocations done in (1) and only a single allocation in (2). If jdub intends to copy construct a new Renderer/InputController/Timer instance in a new shared pointer, what he does is completely correct.

jdub: the key problem is that the error messages you posted are incomplete. Unfortunately the MSVC Error List omits a lot important information. The Output is much more descriptive, including information what types the templates have in the problematic areas. You are also not saying in which lines the errors are happening.

Share this post


Link to post
Share on other sites

You should seriously consider using plain references instead of shared_ptr.  Shared ownership is almost certainly not what you want.  Your DebugLayer doesn't own a renderer, it's just referencing one own by another object.  If you need a nullable reference, use a raw pointer.

 

I can't stress how much time I've spent debugging a the bajillion problems caused by over-zealous use of shared_ptr in production engine code.  Stay far away from it excepting those very rare cases where you actually for-sure need multiple actual owners (and you can't redesign your interface to not need them).

Share this post


Link to post
Share on other sites

 

make_shared allocates a new shared region from the pointer you pass in, i believe.


No. std::make_shared passes whatever arguments it receives to the underlying class's constructor. The difference between
(1) someSharedPointer = std::shared_ptr<MyType>(new MyType(A, B, C, ...));
(2) someSharedPointer = std::make_shared<MyType>(A, B, C, ...);
is soley the fact, that there are two allocations done in (1) and only a single allocation in (2). If jdub intends to copy construct a new Renderer/InputController/Timer instance in a new shared pointer, what he does is completely correct.

jdub: the key problem is that the error messages you posted are incomplete. Unfortunately the MSVC Error List omits a lot important information. The Output is much more descriptive, including information what types the templates have in the problematic areas. You are also not saying in which lines the errors are happening.

 

 

You're right, it uses variadic templates to forward arguments to the std::shared_ptr constructor, and the allocation (whether it's one or two allocs) happens inside the ctor.

So what happens when you have a shared_ptr<T> p, and pass a *p to a make_shared? *p returns a reference, so make_shared passes that reference to the shared_ptr ctor, but there is no ctor that accepts a T&, so wouldn't that be an error too? Or is something else happening that i'm not aware of?

Also, if you have a shared_ptr<T> p, and pass it in a function with p.get(), and that function passes the pointer to make_shared, does that mean two separate reference counts will monitor the same pointer? And deleting both shared pointers would cause either a crash or undefined behaviour?

Share this post


Link to post
Share on other sites

You're right, it uses variadic templates to forward arguments to the std::shared_ptr constructor, and the allocation (whether it's one or two allocs) happens inside the ctor.

Allocations don't happen inside constructors (unless the constructor itself again allocates different memory for its own purposes). Constructors are called on memory which has just been allocated.
 

So what happens when you have a shared_ptr<T> p, and pass a *p to a make_shared? *p returns a reference, so make_shared passes that reference to the shared_ptr ctor, but there is no ctor that accepts a T&, so wouldn't that be an error too? Or is something else happening that i'm not aware of?

This use case would require a valid copy constructor to work. Without knowing more about jdub's design, it's not possible to say whether that's intended or not. But there are scenarios where it is a completely valid and desired operation, though in this case I doubt it.
 

Also, if you have a shared_ptr<T> p, and pass it in a function with p.get(), and that function passes the pointer to make_shared, does that mean two separate reference counts will monitor the same pointer? And deleting both shared pointers would cause either a crash or undefined behaviour?

In general constructing two or more shared pointers from the same raw pointers will result in double deletion and as a consequence undefined behavior. Exceptions to this do exist though. boost::intrusive_ptr does not suffer from that problem if the class sticks to the contract. Custom deleters might be able to guarantee defined behavior as well.
The way jdub uses shared pointers (while still probably not what he intends) does not put him in danger of that though. Edited by BitMaster

Share this post


Link to post
Share on other sites
I think the actual cause of the compiler error here is that the objects passed in are not copyable. So again, the solution is to use assignment on the shared pointer. Edited by King Mir

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!