0

The more I read about RAII, I understand that using the stack is the way to make sure that the code is exception safe.

Does that mean every time I am doing a new() in my code, I am doing something wrong in the sense there is a better way to do it using the RAII principle?

Community
  • 1
  • 1
Moeb
  • 10,527
  • 31
  • 84
  • 110

4 Answers4

2

I think you have not fully grasp what RAII really means. Dynamic allocations, in the same way that other resources like files, connections to databases, etc. are needed in programs. RAII focuses on how to manage those resources, and the way to go is to have the resources managed by objects with automatic storage duration (either stack, or as a member of another object).

That does not mean that every resource must be allocated in the stack, but rather that if you allocate something in the heap, you should delegate the responsibility of managing that memory to an object that is in the stack.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
2

You're not necessarily doing something wrong if you use new, but it's worth checking that you're doing it right.

  • The result of the new expression should be immediately placed under the control of a smart pointer, usually by passing it straight into the constructor.
  • If that smart pointer is a shared_ptr, then you are probably doing it wrong. You should probably use make_shared instead. There are some situations where you shouldn't (use of weak_ptr to large objects), and some where you can't (C++03 without Boost).
  • If you use delete then you pretty much are doing it wrong, unless you are writing your own smart pointer class. And even then, your smart pointer might be able to use another smart pointer to save work.
  • This is not essential, but if you use new solely because the object is "too big for the stack", consider writing a class that acts as a handle to the object, using unique_ptr or scoped_ptr to manage it, so that from the user's point of view the objects they deal with are automatic variables. If you feel like it, you can extend this to the full PImpl idiom. Even if you don't want another class, consider a function that creates the object and returns a unique_ptr to it, which you can then call like auto foohandle = give_me_a_foo();. Then give_me_a_foo contains new, but other user code doesn't, and you encourage the practice of automatically stuffing things into RAII objects.

There are alternative resource-management strategies to RAII in C++, but you'd know about it if you were using them, and that would affect what counts as "wrong".

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
1

Not at all. If the nature of the beast (the allocation requirements) is truly dynamic, eventually it is either going to come from a heap or some severe trickery on the stack pointer.

The best you can do is to use wrappings that scope-guard for you. (I can' tell you how often I use std::vector<> when i need a dynamic temp buffer that is scope protected). It is one of the most ideal reasons to use well maintained and designed libraries like STL, etc. And unlike C# or Java, its predictable, which has tremendous value when truly needed.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • I agree, but I'll mention that, when truly needed, you can get that kind of predictability in both C# and Java. Both languages have features that were included explicitly to provide that ability. – R. Martinho Fernandes Sep 15 '12 at 01:30
  • If there is a way to *guarantee* object destruction at to scope exit in Java or C# I've not seen it, though, admittedly, I don't exactly keep my ear to the rail with "them" =) It is honestly my only real peeve with either language (that and C# is just too damn Micr$oft for me to handle at this point in my career). – WhozCraig Sep 15 '12 at 01:36
  • If you're curious see http://msdn.microsoft.com/en-us/library/yh598w02.aspx and http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html. Not as handy as RAII in C++, but quite useful when you really need it. – R. Martinho Fernandes Sep 15 '12 at 01:40
  • Yeah, I was aware of those. Different topic for different Q&A. To me, finally blocks manually maintained with dispose()es and close()es does not constitute automatic destruction at scope-exit. It will do at those times when you wanna make sure something is cleaned up. I just prefer knowing it will be without having to take a fork in the road. Thanks for the links, btw. been awhile. – WhozCraig Sep 15 '12 at 01:44
  • @Craig: agreed, in particular with reference to the example you used, `Vector/ArrayList` aren't closeable AFAIK. Java argues that it doesn't need to be, because GC doesn't "need" to be predictable, but your point that it *isn't* predictable is true. – Steve Jessop Sep 15 '12 at 08:59
0

No, stack space is very limited so you don't want to put huge things on it, hence the term stack overflow. Also if you need an object to have a lifetime longer than your function, then you can't put it on the stack.

TJD
  • 11,800
  • 1
  • 26
  • 34
  • But most of the times, I have a choice to either use stack or the heap for defining objects. Which one should I use? – Moeb Sep 15 '12 at 01:13
  • For small things used only inside a function, use the stack. For large things with longer lifetimes use the heap. – TJD Sep 15 '12 at 01:14
  • 1
    For heap allocations, you can get the similar safety by using smart pointers. – TJD Sep 15 '12 at 01:19
  • IME, most large objects are allocated dynamically. In that case, what you put on the stack is just a small handle (like std::vector). Stack size is unlikely to be a problem unless you put large arrays as local variables, use large amounts of recursion, or run on an embedded platform. – R. Martinho Fernandes Sep 15 '12 at 01:26