SN1
SN1

Reputation: 43

Any reason to use raw pointers to do RAII? C++11/14

Are there any reasons to still use raw pointers (for managed resources) in C++11/14?

Should resource member variables in a class be held in their own smart pointers for automatic RAII without need for cleanup in destructor?

Is the implementation of smart pointers inlined that there is no overhead in doing so?

Upvotes: 4

Views: 1461

Answers (3)

Klaim
Klaim

Reputation: 69682

Are there any reasons to still use raw pointers (for managed resources) in C++11/14?

I assume that by "managed resources" you mean "owned resources".

Yes there are reasons:

  1. As you are inferring in your question, sometime you want to refer to an object or none, and it can change through time. You have to use a raw pointer in this case, because there is no alternative right now in this specific case. There might be later as there is a proposal about adding a "dumb" non-owning pointer which just clarify the role of the pointer (observe/refer, not own). Meanwhile the recommendation is to avoid new/delete if you can and use raw pointer only as "refers to without owning" kind of re-assignable reference.
  2. You still need raw pointers for implementation of non-raw pointers and any low level RAII construct. Not everybody needs to work on fundamental libraries, but of course if you do, then you need basic constructs to work with. For example in my domain I often have to build up custom "object pool" systems in different ways. At some point in the implementation you have to manipulate raw memory which are not objects yet, so you need to use raw pointers to work with that.
  3. When communicating with C interfaces, you have no other choices than to pass raw pointers to functions taking them. A lot of C++ developers have to do this, so it's just in some very specific regions of your code that you will have to use them.
  4. Most companies using C++ don't have a "modern C++" experience of C++ and work with code that use a lot of pointers where it is not actually necessary. So most of the time when you add code to their codebase, you might be forced by the code-environment, politics, peer-pressure and conventions of the company to use pointers where in a more "modern c++" usage kind of company it would not pass peer-review. So consider the political/historic/social/knowledge-base-of-coworkers context too when choosing your techniques. Or make sure companies/projects you work in match your way of doing things (this might be harder).

Should resource member variables in a class be held in their own smart pointers for automatic RAII without need for cleanup in destructor?

Resource member variables, in the best case, should just be members without being obvious pointers, not even smart pointers. Smart pointers are a "bridge" between code manipulating raw pointers and pure RAII style. If you have total control over some code and it's new code, you can totally avoid making any use of smart pointer in your interfaces. Maybe you will need them in your implementations though. Keep in mind that there is no actual rules, only recommendations of what you could result in if you

Is the implementation of smart pointers inlined that there is no overhead in doing so?

Implementation of standard smart pointers is as efficient as they can be so yes most of their code is inlined. However, they are not always free, it depends on what they actually do. For example, in almost all cases, unique_ptr is exactly one raw pointer, with just additional checks around it's places of use. So it's "free". shared_ptr on the other hand have to maintain a counter of how many other shared_ptr refer to the same object. That counter can be changed on several threads doing copies of the shared_ptr, so it have to be atomic. Changing the value of atomic counters is not always free, and you should always assume that there is a higher cost than copying a raw pointer.

So "it depends".

Just:

  • use RAII as much as you can, without exposing any kind of pointer in your interfaces (smart or not);
  • use standard smart pointers in implementations if you must use owning pointers;
  • use raw pointers only if you need to refer to object, null, or other objects changing through time, without owning them;
  • avoid raw pointers in interfaces except in case of allowing passing optional objects (when nullptr is a correct argument);

You will end-up with code that, from the user's perspective, don't seem to manipulate pointers. If you have several layers of code following these rules, the code will be easier to follow and highly maintainable.

On a related note from: When to use references vs. pointers

Avoid pointers until you can't.

Also note that Sean Parents in his recent talks also consider smart pointers to be raw pointers. They can indeed be encapsulated as implementation details of value-semantic types corresponding to the actual concept being manipulated. Additionally using type-erasure techniques in implementations but never exposing them to the user helps extensibility of some library constructs.

Upvotes: 6

DanDan
DanDan

Reputation: 10562

RAII is more than just wrapping up new and delete - a smart pointer is a form of RAII but RAII is a lot more than that. A good candidate for RAII is when you have any sort of mirroring functions: new/delete, initialise/teardown, stop/start. So your resource should still have its own RAII class - one that performs its cleanup function in its own destructor.

Upvotes: 0

James Kanze
James Kanze

Reputation: 153909

It depends. If the object is fully owned, constructed and destructed by another object, there is a good case for using an std::unique_ptr in that other object. If you have an object which owns several such objects, all of which are dynamically allocated in the constructor, then you have to do something; if the semantics of the usual smart pointers isn't appropriate (which is often the case), then you'll have to invent something: in the case of a graph, for example, you might put the root pointer in a base class (initializing it to null), and have the destructor of the base class clean-up the graph, starting at the root.

Of course, unless your class has some sort of dynamic structure like a graph, you might ask yourself why it is using dynamic allocation to begin with. There are special cases (where, for example, the owned object is polymorphic, and its actual type depends on arguments to the constructor), but in my experience, they aren't that common. In practice, there just aren't that many cases where a smart pointer can be used in an object, much less should be used.

Upvotes: 0

Related Questions