Alright, this has had me stumped on and off for a couple of months now, so I'll see if anyone else can help with this.
So in my main program I have two kinds of structs (solarBody_t, ship_t) that are both derived from the same base class (physical_t). I make a vector of both objects, since I can't put a solarBody and a ship in the same vector. They are both dumb pointer vectors.
I tried putting both in the same vector, using a vector of boost::shared_ptrs. Now, to my understanding, shared_ptrs should have the same semantics and syntax as dumb pointers (e.g. foobar->mass = 42; should work for both). However, just changing the declaration to a vector of boost::shared_ptr to dumb pointers, it gives me an error when I try and push_back something to the vector of shared_ptrs.
From what I can tell, this should work. The boost docs give the example of
boost::shared_ptr<int> p(new int(2));
which is pretty much what I'm doing.
Has anyone had previous experiences with this? Or want to suggest another way to store everything in a vector?
For more details, here's the gist of it (kind of a contradiction of terms, but I made the pun, so there.)
I don't think it'll let you automatically construct a shared_ptr from a bare pointer. push_back is expecting a shared_ptr<foobar_t>, not a bare foobar_t. You should take a look at boost::make_shared and try something like this:
entity_smart.push_back(boost::make_shared<foobar_t>(42));
make_shared has a few advantages: namely, it allocates the pointer control block and the object itself in one allocation and keeps an unmatched new out of your code. It also makes it explicitly clear that you're creating a shared_ptr to an object.
Other than that, yes, the semantics should be basically the same. Keep in mind that shared_ptr may be overkill for what you're doing, though, if you don't actually need to share ownership of the objects.
Lateral thinking:
You do not actually need a shared_ptr here, what you want is a STL(-like) collection in which to store polymorphic values; the collection being the owner.
You have basically two solutions:
use a pointer-aware collection: boost::ptr_vector, from the Pointer Container library.
use a better pointer: std::unique_ptr, from the C++11 Standard
I would still advise boost::ptr_vector even if you have access to C++11 because it provides additional guarantees (null not allowed by default) and sugar coating (dereferencing an iterator gives a reference, not a pointer than you have to dereference once more).
Related
I am brand new to C++ (and Stack Overflow!) so I apologize if this question has already been answered in some capacity, I just wasn't able to find exactly what I was looking for.
In a recent project, I created pointers to pointers (example: Tiger **tigerArray;) and wound up having memory leaks in my program, but I was never able to figure out why. I had a thought that maybe if I had done smart pointers instead of just pointers, that may have solved the problem?
So I'm curious, if I can create a pointer to a pointer, can I create a smart pointer to a smart pointer?
**Sorry I should update, I wasn't allowed to use vectors for this assignment, we had to use arrays
Smart points are generic; you can stick basically anything you want inside one. But you should decide the right tool for the job based on what it is you're trying to achieve. Smart pointers have fairly specific use cases. Pointers to pointers, on the other hand, have a couple different use cases:
pointer arrays of pointer arrays, for implementing 2D arrays. If this is what you're trying to achieve, consider using std::vector<std::vector<T>> or std::array<std::array<T, N>, M> if you know your array will always have size MxN.
pointer to a pointer, as used for modifying another pointer from a function. In this case, you should consider passing by reference. If you really need pointers in your code, you could modify one by passing as T*&, a reference to a pointer to T. But depending on what you're representing, you could just as well pass your data as std::vector<T>&, for example.
Smart pointers exist to automatically manage the lifetime of objects depending on how you want those objects to be used. They don't exist purely as a means of indirection that is open to many different usages, like raw pointers. My advice on which tool to use would be as follows:
If you need a simple resizable array of T, use std::vector<T>.
If you need a 2D resizable array of T, use std::vector<std::vector<T>>.
If you know you will always have N elements in your array, consider using std::array<T, N>.
If you need more structure, such as strict ordering or relationships, consider using std::set, std::map, std::multimap, std::queue, std::stack, etc
About smart pointers:
If you need an object that is light-weight to pass around but only ever has a single owner, or if you need to encapsulate a polymorphic object that is used in a single place, consider std::unique_ptr<T>
If you need an object to be used by multiple places in code which does not have a single sensible place of ownership and instead needs to have distributed ownership, use std::shared_ptr<T>
If you want to modify an object from inside a function such that the object will live for the duration of the function's needs, just pass by reference: T&
If you want to read from but not modify an object in a function where that object will be alive for the duration of the function's needs, pass by reference to const: const T&
EDIT:
After seeing that you are not allowed to use std::vector for your assignment, I realize I'm not really answering your updated question. But I still hope to give you (and future readers) some insight as to what smart pointers are for and what they're not for.
If your instructor is teaching C++ but not allowing you to use vectors, I would criticize them by saying that vector is an immensely important tool on the belt of the modern C++ developer, and its usage is far simpler and safer than the C-style alternatives that are still taught as being C++ in many outdated curriculums. The same goes other tools and techniques such as generally avoiding pointers, avoiding new and delete, and making good use of the containers and algorithms of the standard library, all of which helps you write cleaner, correcter, and efficient code.
I see a lot of cases where people use vector<shared_ptr<T>>. When and why would you use shared_ptr<vector<T>> instead? For me, the latter seems more efficient both in performance and memory-usage. Is it wrong to share a single vector of objects across the application?
Thanks
This use: vector<shared_ptr<T>> will allow you to pass instances of type T from this vector to some other parts of code without fear that they will not be freed. Even if your vector will no longer exist.
shared_ptr<vector<T>> on the other hand protects only vector, its elements of type T are not protected against memory leaks. I assume here that T is of pointer type, if T is non-pointer, then of course you don't have a problem with making memory leak here. Well someone could make T = shared_ptr<T> actually.
Its actually more common to use vector<shared_ptr<T>>, I don't really remember using shared_ptr<vector<T>>.
The point is to never keep, in your code, bare pointers to allocated memory, always keep them in some kind of smart pointer. Its perfectly fine if you implement your own allocate/deallocate mechanism, i.e.. using RAII.
Is it considered good practice to put unique_ptr in an array? Yes, I know, they have unusual copy semantic, but my idea is this:
I have a tiled-based game field. Each pointer in the array points to some game object. When I assign something new to an array element, the previous object is destroyed and a new one is placed.
Another question -- the same about shared_ptr, because sometimes I will use flyweight pattern.
One of unique_ptr's biggest advantages is that it's safe to use in Standard containers like std::vector. std::vector<std::unique_ptr<T>> is no anti-pattern, it's perfectly fine and highly recommended.
In general yes, this is good practice: in that case, the matrix would be the owner of the objects (which should work well in most cases) and other consumers of the object merely retain raw pointers to the objects, if at all.
This is safe and efficient.
On the other hand, consider whether you need pointers at all. If I understand correctly, the only reason for using pointers here is to be able to store polymorphic objects. Consider whether boost::variant may be an alternative here, or some kind of value_ptr (which unfortunately isn’t included in the standard library, but easy to implement).
There's nothing unusual about the copy semantics of unique_ptr; they can be moved but not copied, and hence are entirely suitable for use in a standard container.
You may be thinking of the deprecated auto_ptr which, before move semantics were added to the language, tried to emulate them using destructive copy semantics. This made them very difficult to safely use with standard containers.
Whether you should be storing pointers or objects in the container is another question. Generally, it's better to store objects; unless they're very large or otherwise expensive to move, or unless you need to store (pointers to the common base class of) objects of different types.
If you do want to store pointers, and want the container to manage the lifetime of the objects, then unique_ptr is the best choice. shared_ptr is also suitable, if you want to share ownership with other entities, or if you want to use weak_ptr to determine whether the object has been removed from the array.
In general unique_ptr is more performant than shared_ptr because it doesn't do reference counting, however one place must have ownership. This is risky because if you have:
vector<unique_ptr<GameObject>> v;
You would take a reference to it with:
GameObject* p = v[42].get();
and then if position 42 is deleted or replaced, p will be a hanging pointer.
However:
vector<shared_ptr<GameObject>> v;
shared_ptr<GameObject> p = v[42];
Will keep the underlying object around for p even if v[42] is deleted - but you have the overhead of the reference count update.
My suggestion would be to prefer shared_ptr because its safer, unless performance becomes an issue.
I love this book, sadly it does not cover smart pointers as they were not part of the standard back then. So when reading the book can I fairly substitute every mentioned pointer by a smart pointer, respectively reference?
"Smart Pointer" is a bit of a misnomer. The "smart" part is that they will do some things for you, whether or not you need, want, or even understand what those things are. And that's really important. Because sometimes you'll want to go to the store, and smart pointers will drive you to church. Smart pointers solve some very specific problems. Many would argue that if you think you need smart pointers, then you're probably solving the wrong problem. I personally try not to take sides. Instead, I use a toolbox metaphor - you need to really understand the problem you're solving, and the tools that you have at your disposal. Only then can you remotely expect to select the right tool for the job. Best of luck, and keep questioning!
Well, there are different kinds of smart pointers. For example:
You could create a scoped_ptr class, which would be useful when you're allocating for a task within a block of code, and you want the resource to be freed automatically when it runs of of scope.
Something like:
template <typename T>
class scoped_ptr
{
public:
scoped_ptr(T* p = 0) : mPtr(p) {}
~scoped_ptr() { delete mPtr; }
//...
};
Additionally you could create a shared_ptr who acts the same but keeps a ref count. Once the ref count reach 0 you deallocate.
shared_ptr would be useful for pointers stored in STL containers and the like.
So yes, you could use smart pointers for most of the purposes of your program.
But think judiciously about what kind of smart pointer you need and why.
Do not simply "find and replace" all the pointers you come across.
No.
Pointers which represent object ownership should be replaced by smart pointers.
Other pointers should be replaced by iterators (which in the simplest case is just a typedef for a raw pointer, but no one would think they need to delete).
And of course, the implementation code for smart pointers and iterators will continue to need raw pointers.
How is the destructor for the vector managed when adding elements to this list? Is the object destroyed correctly when it goes out of scope? Are there cases where it would not delete the object correctly? For example what are the consequences if "table" was a child of object, and we added a new table to a vector of object pointers?
vector <object*> _objectList;
_objectList.PushBack(new object);
Since you're making a vector of "bare" pointers, C++ can't possibly know that the pointers in question are meant to have "ownership" of the objects they point to, and so it will not call those objects' destructors when the pointer goes away. You should use a simple "smart" pointer instead of a "bare" pointer as the vector's item. For example, Boost's shared_ptr would be perfectly adequate for the task (although you can surely do it with "cheaper", lighter-weight approaches, if you don't want to deal with Boost as a whole and have no other need for smart pointers in your code).
Edit: since you (the OP) say that using a framework such as Boost is not feasible, and a couple comments usefully point out that even wrapping std::auto_ptr doesn't really qualify as a decent shortcut, you may have to implement your own smart pointers (or, if you find an open-source, stand-alone smart pointer template class that looks usable, audit it for compliance with your requirements). This article is a useful primer to smart pointers in C++, whether you have to roll your own or audit an existing implementation.
You could use bost 'ptr_vector'. It will automatically destruct objects that the items point to when they are either deleted or the instance of ptr_vector goes out of scope. More info is available here.
In your case, the object pointers are destroyed properly, but the actual objects themselves won't be touched. The STL properly destructs all contained elements - but will not implicitly dereference pointers to types.
STL Vectors make a copy of whatever you put in there, and ultimately delete that copy.
So in this case, the vector is storing a pointer to an object - not the object itself. So it makes a copy of the pointer, and deletes the pointer. But, as Chris said, the object itself will not be deleted.
So, solutions:
If you don't really need to use pointers, then don't:
vector <object> _objectList;
_objectList.PushBack(object());
If you do need to use pointers, you can either use a smart pointer (which handles reference counting for you, and will delete the object along with the pointer), as Alex suggested, or use a ptr_vector, as Igor mentioned.