Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ shared_ptr of stack object

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);
like image 665
Short Avatar asked Sep 12 '11 05:09

Short


People also ask

Should I use unique_ptr or shared_ptr?

Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.

What is shared_ptr used for?

The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.

What is boost :: shared_ptr?

shared_ptr is now part of the C++11 Standard, as std::shared_ptr . Starting with Boost release 1.53, shared_ptr can be used to hold a pointer to a dynamically allocated array. This is accomplished by using an array type ( T[] or T[N] ) as the template parameter.

Is shared_ptr copy thread safe?

std::shared_ptr is not thread safe. A shared pointer is a pair of two pointers, one to the object and one to a control block (holding the ref counter, links to weak pointers ...).


3 Answers

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));
like image 142
James McNellis Avatar answered Oct 17 '22 08:10

James McNellis


You should probably define the semantics of your class more clearly. If you want RenderView to be the owner of the RenderModel it should create it on its own (maybe get in the constructor some identifier to use with a factory).

I've seen classes that receive ownership of objects, and it was defined explicitly that this objects must be on the heap, but this is, to my opinion, error prone, just like the error you now encountered. You can not give a stack object to a smart pointer that expects it to be on the heap (because it will use delete on it when it wants to clean it).

like image 33
selalerer Avatar answered Oct 17 '22 08:10

selalerer


The way you described what you want to do is completely wrong. In the MVP design pattern, the view should not access the model directly, but should send commands to the presenter (by calling presenter's functions).

Anyway, other's have answered your question : your model object has to be allocated on the heap, like this :

std::shared_ptr<RenderModel> ptr( new RenderModel );
RenderView v;
v.SetModel(ptr);

otherwise your shared_ptr object is going to try to delete a stack object.

like image 2
BЈовић Avatar answered Oct 17 '22 06:10

BЈовић