#2 Members - Reputation: 303
Posted 17 June 2012 - 10:02 AM
I always use smart pointers, unless there's a good reason not to. A good reason can be performance in tight loops or something like that, but those cases are rare and should never leak out of your interfaces. Note that using smart pointers doesn't mean 'don't think about ownership', which often results in overusing shared pointers. Quite the opposite in fact: different types of smart pointers are a great way to explicitly state ownership of an object.
#3 Members - Reputation: 1298
Posted 17 June 2012 - 11:03 AM
C++ object lifetime should be managed with the following priority:
1) Stack based. This is the way C++ was designed for. If you can make it stack based, do it. Cleanest and fastest code is obtained this way.
2) Clean ownership heap based with new and delete. One guy creates the object, same guy is responsible to delete it.
3) unique_ptr .. which is like 2 but if you are willing to write unique_ptr<blabla>, .get() and all that nonsense over and over again to AVOID 1 SINGLE CALL TO "delete" in your destructor.
4) shared_ptr . That is, when the ownership is _really_ SHARED, so you can't possibly predict the lifetime and ownership of an object and this is used and kept alive by different objects.
So while I can't possibly think about using option 3 ever.. I know there are scenarios where 4 is useful. I use shared_ptr for materials for example, and it works ok.
Also, shared_ptr can create leaks that are REALLY hard to detect if you manage to create a reference loop.
All the above is IMO IMO IMO .. smart pointes just made it into the C++11 standard and there is still no book about best practices out yet... so the jury is still out on this one.
Edited by kunos, 17 June 2012 - 11:04 AM.
#4 Members - Reputation: 2042
Posted 17 June 2012 - 11:12 AM
IMHO, correctness should come before aesthetics every time. typedefs can be a big help, as can auto if available.Actually Stoustrup himself suggests to use smart pointers as "last resort", expecially shared_ptr . The danger of introducing smart pointers as standard in C++ is, IMO, the urge that people have to use them everywhere, and I believe that is wrong for a series of reasons but the top one is: they really make C++ uglier than already is, having this const shared_ptr<Node>& all over the place is really ugly.
I definitely agree with this.C++ object lifetime should be managed with the following priority:
1) Stack based. This is the way C++ was designed for. If you can make it stack based, do it. Cleanest and fastest code is obtained this way.
If you've got unique_ptr, you've quite possibly got auto too. You get brevity with additional safety for free. And the more you standardise on smart pointers, the less you need .get().2) Clean ownership heap based with new and delete. One guy creates the object, same guy is responsible to delete it.
3) unique_ptr .. which is like 2 but if you are willing to write unique_ptr<blabla>, .get() and all that nonsense over and over again to AVOID 1 SINGLE CALL TO "delete" in your destructor.
Besides, without the use of something like unique_ptr, one would typically be required to make more than one call to delete where error handling occurs, early returns, inside surrounding catch clauses, etc.
#5 Members - Reputation: 1599
Posted 17 June 2012 - 01:09 PM
The problem with auto is that it can also be overused. You get safety and smaller lines of code. But it's also harder to grok for another human being who didn't write the code. You have no idea what the variable type holds unless you make more use of advanced IDE tools. Furthermore I'm starting to see programmers using auto for almost every single variable they declare (being completely unnecessary btw).
Using auto inside a template is incredibly useful because by definition, templates don't know the type of objects that are being passed into them until compiled.
But IMHO, outside of a template, the usage of auto should only be used as a last resort; typically where using auto has a real benefit over explicitly declaring the type of the variable. This isn't an old problem, interpreted languages (Python, Lua) already have this issue. It's not a problem about safety, style, or aesthetics. It's a problem of deeply understanding what your (or someone else's) code is doing, which is very important in close-to-the-metal languages like Asm, C & C++.
In Python & Lua, this problem is alleviated because one can write "print( variable )" and they also have an interactive interpreter. In C++ we have none of that.
#6 Members - Reputation: 354
Posted 17 June 2012 - 02:21 PM
Not that there aren't any reasons to use smart pointers, but I tend to structure code in a way where I don't need them. Sometimes this can't be done, and sometimes it'd just be too much work to refactor the code. I know of a multi-million line program that is littered with shared pointers, and occasionally those developers will run into a problem with them.
#7 Members - Reputation: 763
Posted 17 June 2012 - 03:31 PM
Anyone who dismisses smart pointers with "all it saves you is a delete in the destructor" has apparently never heard of exception safety.
#8 Members - Reputation: 525
Posted 17 June 2012 - 04:06 PM
Can't think of any time when I've had to resort to shared_ptr, there always seems to be a better option.
#10 Members - Reputation: 5802
Posted 17 June 2012 - 08:52 PM
When I do have to use a pointer (e.g., for the return value of a factory), I often end up using a shared_ptr because I don't trust the caller of that code (usually me) with not messing up the ownership. But I don't feel very strongly about this choice and perhaps I'll change it in the future.
#11 Moderators - Reputation: 6636
Posted 17 June 2012 - 09:18 PM
#12 Members - Reputation: 629
Posted 18 June 2012 - 02:42 AM
I will also say that I've found unique_ptr is very handy for creating temporary buffers of dynamic size, or ones of static size that you don't necessarily want eating up your stack.
i.e:
std::unique_ptr<char[]> buffer( new char[64 * 1024] );
Then you don't need to worry about exception safety or calling delete in every exit point of your function.
#13 Members - Reputation: 284
Posted 18 June 2012 - 03:56 AM
3) unique_ptr .. which is like 2 but if you are willing to write unique_ptr<blabla>, .get() and all that nonsense over and over again to AVOID 1 SINGLE CALL TO "delete" in your destructor.
Somewhat agree, somewhat disagree with this point.
I don't use exceptions in my C++, but using a unique or scoped pointer makes your code more exception safe.
Even if you don't use exceptions, for allocations within a function, it take out a lot of the programmer overhead of memory management. Then, for consistency's sake, I use scoped pointer wrapper for member variables too.
I do agree that littering code with myPtr.get() is a bit of a pain in the neck though!
#14 Members - Reputation: 763
Posted 18 June 2012 - 04:10 AM
#16 Members - Reputation: 629
Posted 18 June 2012 - 07:10 PM
Assuming the pointer must not be null, is there any reason to use pointer.get() over &*pointer? I've been using the latter as it works for pretty much any pointer-like type (raw pointers, boost smart pointers, qt smart pointers).
From a functional standpoint, no. From a code clarity standpoint, yes. pointer.get() is clear in it's intent, &*pointer looks like a bug.
That being said, if your code is littered with .get() then you may have a more fundamental code smell; overusing pointers, period. You should almost always prefer to pass by const reference rather than by pointer unless you have a good reason to pass a pointer (i.e. an output parameter, a raw buffer, or interfacing to a third-party library). So most access to the object should either be pointer-> or *pointer rather than pointer.get().
#17 Members - Reputation: 173
Posted 19 June 2012 - 01:59 AM
That feeling of safety might lead to a messy flow in your game. Using normal pointers forces you to have a clean flow in your code, a flow of initialization, the ownership for each object is clearly defined, etc.
I've seen this a lot in school projects (university), and to some degree even in some engines used to make games
You can end up with some object shared between two or three others, with no clearly defined owner and this might give you a lot of headaches.
Edited by clickalot, 19 June 2012 - 02:01 AM.
#18 Members - Reputation: 682
Posted 19 June 2012 - 02:41 AM
1, Always use clear and explicit ownership.
2, Prefer scoped pointer (unique_ptr) to raw pointer.
3, Avoid shared pointer unless there is good reason. Policy 1 implicits that shared pointer should be avoided. The only good reason to use shared pointer I've found recently is that, when there is no clear ownership of the resource. Such as in a script binding, the C++ resource may be freed by script engine without knowing by your code.
With those policies, I use scoped pointer extensively but I never overuse shared pointer, and I rarely get memory leak or bad pointer.
Just my 2 cents
http://www.cpgf.org/
cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.
v1.5.5 was released. Now supports tween and timeline for ease animation.
#19 Members - Reputation: 337
Posted 19 June 2012 - 07:07 AM
But I have a case where I use a unique_ptr as its a factory function that creates the object.. I then move this pointer into a owning container.. but I also have to set a currently selected object in another class.. should I rather use a shared_ptr in this case and use a weak_ptr for where I set the currently selected object? Or should I use a raw pointer for the selected object and get the raw pointer out of the unique pointer like I do below?
class A
{
};
class B
{
public:
void SetCurrent(A* current) { m_current = current; }
private:
A* m_current;
};
B b;
std::vector<std::unique<A>> vec;
std::unique<A> p0 = CreateA();
std::unique<A> p1 = CreateA();
vec.push_back(std::move(p0));
vec.push_back(std::move(p1))
b.SetCurrent(p1.get());
Edited by Nanook, 19 June 2012 - 07:10 AM.
#20 Members - Reputation: 568
Posted 19 June 2012 - 11:51 AM
should I rather use a shared_ptr in this case and use a weak_ptr for where I set the currently selected object? Or should I use a raw pointer for the selected object and get the raw pointer out of the unique pointer like I do below?
Don't mix raw pointers with smart pointers, by storing raw pointers you completely negate the safety and validity of your smart pointers. You can .get() the raw pointer for local operations where there is no risk of memory corruption.
In this case you probably want to pass a shared_ptr to A and store it as either a shared_ptr or weak_ptr. If you actually intend to transfer ownership of A into B, then you can pass unique_ptr.
unique_ptr is not as useful when you have a pointer that you need to pass around a lot. unique_ptr is very useful for heap-allocated objects within initialization functions that might fail early, relieving you of a lot of ugly cleanup work. I would also agree that unique_ptr is useful for returning objects from a factory, but not so much if there is a cache involved. If there is a cache, what you actually have is shared ownership (this cache holds onto one reference while another reference is grabbed by the object calling the factory).






