I have been learning managed pointers lately and ran into the following scenario.
I am implementing a model/controller class for a game view. My view, will render things in the model. Pretty straight forward. In my main function, I instantiate all three like this:
RenderModel m;
m.AddItem(rect); // rect gets added just fine, it's an "entity" derivee
RenderView v;
v.SetModel(m);
My render view class is pretty straightforward:
class RenderView
{
public:
explicit RenderView();
~RenderView();
void Update();
void SetModel(RenderModel& model);
private:
// disable
RenderView(const RenderView& other);
RenderView& operator=(const RenderView& other);
// private members
boost::scoped_ptr<RenderModel> _model;
};
The implementation for setView is pretty standard:
void RenderView::SetModel(RenderModel& model)
{
_model.reset(&model);
}
The key to this is, the view stores a model in a smart pointer. However in main, the model was allocated on the stack. When the program exits, the memory gets deleted twice. This makes sense. My current understanding tells me that anything which gets stored in a smart_ptr (of any kind) should not have been allocated on the stack.
After all the above setup, my question is simple: how do I dictate that a parameter was not allocated on the stack? Is accepting a smart pointer as a parameter the only solution? Even then I could not ensure that someone using my view class could not do something incorrect such as:
// If I implemented SetModel this way:
void RenderView::SetModel(const std::shared_ptr<RenderModel>& model)
{
_model.reset(&*model);
}
RenderModel m;
RenderView v;
std::shared_ptr<RenderModel> ptr(&m); // create a shared_ptr from a stack-object.
v.SetModel(ptr);
how do I dictate that a parameter was not allocated on the stack?
Yes, require the caller to provide a std::shared_ptr<RenderModel>
. If the caller misconstructs the std::shared_ptr
, that's the caller's problem, not yours.
If you intend for a RenderView
to be the sole owner of a particular RenderModel
, consider having the function take a std::unique_ptr
or std::auto_ptr
instead; this way it is clear that the caller should not retain ownership of the object after it calls the function.
Alternatively, if RenderModel
is cheap to copy, make a copy of it and use the copy:
_model.reset(new RenderModel(model));