views:

1176

answers:

11

I'm curious as I begin to adopt more of the boost idioms and what appears to be best practices I wonder at what point does my c++ even remotely look like the c++ of yesteryear, often found in typical examples and in the minds of those who've not been introduced to "Modern C++"?

+4  A: 

These days I've pretty much abandoned all use of raw pointers. I've even started looking through our code base for places where raw pointers were used and switched them to a smart pointer variant. It's amazing how much code I've been able to delete by doing this simple act. There is so much code wasted on lifetime management of raw C++ pointers.

The only places where I don't use pointers is for a couple of interop scenarios with other code bases I don't have control over.

JaredPar
+2  A: 

I still use regular pointers in resource-sensitive code or other code that needs tiny footprint, such as certain exceptions, where I cannot assume that any data is valid and must also assume that I am running out of memory too.

Managed memory is almost always superior to raw otherwise, because it means that you don't have to deal with deleting it at the right place, but still have great control over the construction and destruction points of your pointers.

Oh, and there's one other place to use raw pointers:

boost::shared_ptr<int> ptr(new int);
coppro
I thought there was no overhead with the boost: pointer classes? Doesn't the compiler optimize everything away?
ApplePieIsGood
There is not a huge amount of overhead on scoped pointer classes, but it has to exist, and shared pointers need a reference count and the associated mechanisms. I always follow rule 1 though; profile first, then optimize.
coppro
Can't think of a single time of 15 years of C++ coding I've ever needed to explicitly allocate a single int on the heap. An array of int:s is another matter, but then there's always std::vector<int>.
Andreas Magnusson
+1  A: 

If you have circular data structures, e.g., A points to B and B points back to A, you can't use naively use smart pointers for both A and B, since then the objects will only be freed extra work. To free the memory, you have to manually clear the smart pointers, which is about as bad as the delete the smart pointers get rid of.

You might thing this doesn't happen very often, but suppose you have Parent object that has smart pointers to a bunch of Child objects. Somewhere along the way someone needs to look up a the Parent for a Child, so they add a smart pointer member to Child that points back to the parent. Silently, memory is no longer freed.

Some care is required. Smart pointers are not equivalent to garbage collection.

David Norman
This is what boost::weak_ptr is for, if you have it. So you can still use smart pointers rather than raw, just not all of the smart pointers will be shared_ptr.
Steve Jessop
Absolutely boost::weak_ptr is another way to solve the circular reference problems, but I think my point still holds: You have to pay attention and not just blindly use whatever smart pointers you have.
David Norman
I guess I'm assuming that when the questioner says "adopted boost's smart pointers" he means all of them, used appropriately, not just shared_ptr used for everything. You're right that not all readers will appreciate this :-)
Steve Jessop
+7  A: 

I don't use shared_ptr almost at all, because I avoid shared ownership in general. Therefore, I use something like boost::scoped_ptr to "own" an object, but all other references to it will be raw pointers. Example:

boost::scoped_ptr<SomeType> my_object(new SomeType);
some_function(my_object.get());

But some_function will deal with a raw pointer:

void some_function(SomeType* some_obj)
{
  assert (some_obj);
  some_obj->whatever();
}
Nemanja Trifunovic
Beat me to it - I was going to say that passing by raw pointer can be used by convention to imply that the callee will not retain a reference to the object (or at least not in a way which affects resource management).
Steve Jessop
How can you retain a reference to the object in a way that doesn't affect resource management? Once the resource is destroyed, the retainer of that reference must now be aware of the fact, right?
ApplePieIsGood
It is all about scopes. Put the owner in the outmost scope the object is going to be used, and then just pass pointers to it within that scope. No reference is allowed to live in a broader scope than the owner and thus it is guaranteed to point to a valid object.
Nemanja Trifunovic
Why don't you pass the scoped_ptr by reference?
Patrick
Because if some_function() accepts a raw pointer, then I can also create my_object on stack, and just pass its address to some_function(). in fact, that's what I would do in most cases.
Nemanja Trifunovic
@Patrick: I think passing a scoped_ptr can be a bit awkward compared with a raw pointer. If you later want to refactor, so that the thing passed is const, then the change is from scoped_ptr<T> to scoped_ptr<const T> instead of from T* to const T*. This is not one of C++ templates' strong points.
Steve Jessop
References people! Unless you want to explicitly allow calling a function with a nullptr, I'd say references is the way to go. Why catch an error at runtime when the compiler will happily do it for you?
Andreas Magnusson
+2  A: 

I still use raw pointers on devices that have memory mapped IO, such as embedded systems, where having a smart pointer doesn't really make sense because you will never need or be able to delete it.

Cristián Romo
+4  A: 

I find the primary difference between 'modern' C++ and the old* stuff is careful use of class invariants and encapsulation. Well organised code tends naturally to have fewer pointers flying around. I'm almost as nervous swimming in shared_ptrs as I would be in news and deletes.

I'm looking forward to unique_ptr in C++0x. I think that will tidy away the few (smart) pointers that do still roam the wild.

*still unfortunately very common

James Hopkin
+4  A: 

Certainly any time you're dealing with a legacy library or API you'll need to pass a raw pointer, although you'll probably just extract it from your smart pointer temporarily.

In fact it is always safe to pass a raw pointer to a function, as long as the function does not try to keep a copy of the pointer in a global or member variable, or try to delete it. With these restrictions in place, the function cannot affect the lifetime of the object, and the only reason for a smart pointer is to manage the object lifetime.

Mark Ransom
+1  A: 

I'm writing C++ that has to co-exist with Objective C (using Objective C++ to bridge). Because C++ objects declared as part of Objective C++ classes don't have constructors or destructors called you can't really hold them there in smart pointers.

So I tend to use raw pointers, although often with boost::intrustive_ptr and an internal ref count.

Phil Nash
A: 

Not that I would do it, but you need raw pointers to implement, say, a linked list or a graph. But it would be much smarter to use std::list<> or boost::graph<>.

Max Lybbert
+5  A: 

Just a few off the top of my head:

  • Navigating around in memory-mapped files.
  • Windows API calls where you have to over-allocate (like a LPBITMAPINFOHEADER).
  • Any code where you're munging around in arbitrary memory (VirtualQuery() and the like).
  • Just about any time you're using reinterpret_cast<> on a pointer.
  • Any time you use placement-new.

The common thread here is "any situation in which you need to treat a piece of memory as something other than a resource over which you have allocation control".

Tim Lesher
Whenever I need to allocate memory (say to hold a BITMAPINFOHEADER with extra bytes at the end), I'd use a std::vector if possible, then there's no delete to worry about and if a Windows API would tell me my allocated memory is not enough, std::vector::resize() is sweet.
Andreas Magnusson
Of course. You can still use standard containers or smart pointers to manage the underlying memory when possible. The point is when you're going to talk to a Windows API, you're going to cast to a raw pointer, which is what the original question asked about.
Tim Lesher
Also for interfacing with the "outside". If your user requests a buffer, then it gets a buffer, not a smart pointer.
Edouard A.
A: 

talking to code that you didn't write is kinda a big deal. its not just windows and legacy.

Dustin Getz