21

Objective C has introduced a technology called ARC to free the developer from the burden of memory management. It sounds great, I think C++ developers would be very happy if g++ also has this feature.

ARC allows you to put the burden of memory management on the (Apple LLVM 3.0) compiler, and never think about retain, release and autorelease ever again

So, if LLVM3.0 can do that, I think g++ also can free C++ developers from the tough jobs of memory management, right?

Is there any difficulties to introduce ARC to C++?

What I mean is: If we don't use smart pointers, we just use new/new[], is it possible for a compiler to do something for us to prevent memory leaks? For example, change the new to a smart pointer automatically?

Mat
  • 188,820
  • 38
  • 367
  • 383
camino
  • 8,673
  • 19
  • 53
  • 94
  • 4
    I admit I don't know anything about ARC, but C++ has smart pointers (shared_ptr, unique_ptr etc) for automatic memory management. Have you checked them? – Asha Mar 16 '12 at 08:23
  • 4
    If you're "doing it right", you should (almost) never need to use `new`/`delete` in C++. – user541686 Mar 16 '12 at 08:25
  • 3
    @Mehrdad: `new` is fine, `delete` is the evil guy :) – orlp Mar 16 '12 at 08:29
  • 2
    @nightcracker: No they are equally evil.A `new` without a `delete` is evil too :) – Alok Save Mar 16 '12 at 08:31
  • 1
    @Als: well with a smart pointer the `delete` is done automatically :) – orlp Mar 16 '12 at 09:40
  • @Mehrdad That depends on the application domain. There are domains where dynamic allocation is rare or non-existant. In most cases, however, you'll have polymorphic entity objects, which you have to `new` and `delete`. – James Kanze Mar 16 '12 at 10:08
  • @nightcracker "with a smart pointer, the `delete` is done automatically": but not at the proper moment. Remember, `delete` is not just memory management. – James Kanze Mar 16 '12 at 10:08
  • 1
    For me, the biggest difficulty to introducing ARC to C++ would be that I'd immediately stop using the compiler that does this. C++ does not have built-in ARC, and it doesn't have it for a reason. C++, like C, makes you pay for what you use, not for anything extra -- and in particular not for would-be-smart management stuff. You can get along perfectly well and trouble-free without built-in ARC if you use the part of your body that's located in between your ears. – Damon Aug 09 '13 at 12:08
  • 1
    Or, put differently, if one doesn't like the way C++ works for whatever reason, that is fine. But then, one should just use something different instead of making C++ something that it isn't. – Damon Aug 09 '13 at 12:10

9 Answers9

20

C++ has the concept of Resource Allocation is Initialization(RAII) & intelligent use of this method saves you from explicit resource management.

C++ already provides shared_ptr which provides reference counting.

Also, there are a host of other Smart pointers which employ RAII to make your life easier in C++.

Community
  • 1
  • 1
Alok Save
  • 190,255
  • 43
  • 403
  • 518
  • 2
    Also: you should prefer values and automatic variables to dynamic allocation, and reserve the latter for when it's really needed. – Cat Plus Plus Mar 16 '12 at 08:27
  • 2
    @Camino: What Cat said isa valuable piece of advice, Do follow that. This [C++-Faq Entry](http://stackoverflow.com/questions/6500313/in-c-why-should-new-be-used-as-little-as-possible) is a good read for you in this regards. – Alok Save Mar 16 '12 at 08:30
  • 4
    But the OP's question is about *Automatic* RC. The point of ARC is that the compiler introduces the correct lifecycle/ownership instructions where they should belong. That is, the source code will not have any management instructions other than the equivalent of `new` - and the question is thus, if LLVM can do it for Objective-C, would it be technically feasible as a compiler option in C++? If not, what's the difference between C++ and OC that makes it so? – entonio May 06 '13 at 19:15
  • `shared_ptr` however always uses a mutex/critical section, even when you don't pass a pointer to another thread. – sashoalm Jan 07 '14 at 10:46
  • @entonio What's the functional difference between ARC and shared_ptr? In both cases, the compiler adds in the reference counting instructions... – weberc2 Nov 20 '15 at 20:47
  • Wrt functional difference and intelligence, [read this post](http://www.galloway.me.uk/2012/01/a-look-under-arcs-hood-episode-2/). That's not achievable via templates – OCTAGRAM Feb 10 '17 at 21:21
19

This is a good question. ARC is much more than just an implementation of smart pointers. It is also different from garbage collection, in that it does give you full control over memory management.

In ARC you know exactly when objects are going to be released. The reason people think is isn't true, is that there's no explicit "release" call that you write. But you know when the compiler will insert one. And it's not in some garbage collection step, it's inline when objects are considered no longer needed.

It contains a compiler step that analyzes the code and tries to find any redundant sequences of incrementing and decrementing reference counts. This could probably be achieved by an optimizing C++ compiler if it was given a smart pointer implementation that its optimizer could see through.

ARC also relies on the semantics of objective c. Firstly, pointers are annotated to say whether they are strong or weak. This could also be done in C++, just by having two different pointer classes (or using smart and vanilla pointers). Secondly, it relies on naming conventions for objective c methods to know whether their return values should be implicitly weak or strong, which means it can work alongside non-ARC code (ARC needs to know if your non-ARC code intended to return an object with a +1 reference count, for example). If your "C ARC" didn't sit alongside non-"C ARC" code you wouldn't need this.

The last thing that ARC gives you, is really good analysis of your code to say where it thinks leaks may be, at compile time. This would be difficult to add to C++ code, but could be added into the C++ compiler.

Jan Svarovsky
  • 236
  • 2
  • 5
8

There's no need. We have shared pointers that do this for us. In fact, we have a range of pointer types for a variety of different circumstances, but shared pointers mimic exactly what ARC is doing.

See:

std::shared_ptr<>

boost::shared_ptr<>

Moo-Juice
  • 36,340
  • 10
  • 69
  • 121
  • I wonder if they do? I don't know anything about ARC, so I can't say for sure. But anything using reference counting systematically has to have some sort of special handling for cycles. Otherwise, it will cause more harm than good. (After all, it's only a very small minority of cases where you'd use `std::shared_ptr<>`.) – James Kanze Mar 16 '12 at 08:37
  • @JamesKanze, I likened shared_ptr's more due to the reference counting semantics mentioned in the OP. `unique_ptr` has no need of this, though it is true that all these smart pointer classes mean we're free to not worry about the `delete`. – Moo-Juice Mar 16 '12 at 08:38
  • what puzzled me is ARC is a feature of complier , but smart pointer has no relation-ship to complier ,right? – camino Mar 16 '12 at 08:52
  • @Camino, correct. The C++ compiler has no concept of smart pointers, reference counting, etc. These are features provided by libraries such as STL, Boost, et al. – Moo-Juice Mar 16 '12 at 08:54
  • @Moo-Juice, do you have any idea that why LLVM3.0 can help to improve memory-management? I mean ARC declare it was a compiler feature, but I have no idea how compiler can solve the memory-managament issue. – camino Mar 16 '12 at 09:06
  • @Moo-Juice `unique_ptr` is probably more useful than `shared_ptr` in C++, but there is nothing which means that you don't have to worry about object lifetime---even in languages with garbage collection, like Java, entity objects have a finite lifetime determined by the program logic, and often need special handling at the end of their lifetime. (The Java convention I've seen here is to use a function called `dispose()`.) – James Kanze Mar 16 '12 at 10:06
  • @JamesKanze, Agreed - but I wasn't delving in to object lifetime here, more the reference counting mention - though I agree the two are intrinsically linked, and you're right about `unique_ptr`'s usefulness. – Moo-Juice Mar 16 '12 at 10:12
4

Recently I wrote some Objective-C++ code using Clang and was surprised to find that Objective-C pointers were actually handled as non-POD types in C++ that I could use in my C++ classes without issues.
They were actually freed automatically in my destructors!
I used this to store weak references in std::vectors because I couldn't think of a way to hold an NSArrary of weak references..
Anyways, it seems to me like Clang implements ARC in Objective-C by emulating C++ RAII and smart pointers in Objective-C. When you think about it, every NSObject* in ARC is just a smart pointer (intrusive_ptr from Boost) in C++.
The only difference I can see between ARC and smart pointers is that ARC is built into the language. They have the same semantics besides that.

Tal Zion
  • 1,081
  • 1
  • 11
  • 21
3

One of the reasons C++ is used at all is full control over memory management. If you don't want that in a particular situation there are smart pointers to do the managing for you.

Managed memory solutions exist, but in the situation C++ is chosen rightfully (for large-scale big applications), it is not a viable option.

orlp
  • 98,226
  • 29
  • 187
  • 285
  • @Cat Plus Plus: perhaps, but in the absolutely most performance critical sections of code (read: standard containers, for example) the overhead of managed pointers (how miminal that is) may not be wanted. But in 99% of the scenario's you're right of course. – orlp Mar 16 '12 at 08:26
  • 3
    There's no overhead to `unique_ptr`, which should be the default choice of a pointer. – Cat Plus Plus Mar 16 '12 at 08:28
  • @Cat Plus Plus: then please disregard what I said, sometimes I'm being stupid (being the C++ noob I am :)). – orlp Mar 16 '12 at 08:29
  • @CatPlusPlus: What about the overhead associated with the function calls (constructor and destructor)? – Asha Mar 16 '12 at 08:31
  • @CatPlusPlus Why do people make statements like this? It depends a lot on the application domain, but in a lot of applications, almost all delete's will be `delete this;`, or will be done (manually) by the transaction manager. – James Kanze Mar 16 '12 at 08:32
  • @CatPlusPlus `unique_ptr` can't be the default choice, since in most cases, it's not available (yet). But ownership by `unique_ptr` or `auto_ptr` is normally only temporary, to ensure exception safety until the object is fully initialized (and it is only used in cases where you can't ensure full initialization in the constructor). If you leave the object in a `unique_ptr`, why do a dynamic allocation to begin with? – James Kanze Mar 16 '12 at 08:35
  • 1
    @JamesKanze: `boost::scoped_ptr` then. `unique_ptr` models exclusive ownership, not temporary ownership, whatever that would be. It differs from raw pointers only by safety level (you can extract non-owning pointer via `get` and pass it along wherever you please). You should never have an owning raw pointer, and this is a statement of every C++ expert I know. – Cat Plus Plus Mar 16 '12 at 11:09
  • @Asha: There's no more overhead than using `new` and `delete` directly. Function calls will be inlined, and even if not, negligible. – Cat Plus Plus Mar 16 '12 at 11:14
  • @CatPlusPlus What they model is one thing; what they are actually used for is another. Most code I've seen uses `std::auto_ptr` for this, but all three work, since all three have a `release` method. And owning pointers should be very rare; objects aren't normally "owned" by pointers (or anything else, in an OO model). (And I've never heard of a C++ expert who says "never".) – James Kanze Mar 16 '12 at 11:26
  • The Devil's advocate says: If you call `delete` manually, you know exactly who owns that object and know exactly what its lifetime was and that you are absolutely safe to delete it at that time. While smart pointers have their uses, I still think really knowing how the design of your application fits together and truly understanding the lifetime of your objects is just as important. –  Mar 16 '12 at 13:39
  • @James - while understanding object lifetime is very important, though the function that object performs during its lifetime is somewhat more important than the exact moment of its death(if it doesn't go away before fulfilling its destiny of course). And sometimes a poor guy like me needs to concentrate on the most important - just to get something done. That's why those smart things are so important for us, guys with much smaller brains then yours, James... And you've got a big one, I know what I'm talking about! – kerim Mar 18 '13 at 13:52
3

What's the advantage of using ARC rather than full garbage collection? There was a concrete proposal for garbage collection before the committee; in the end, it wasn't handled because of lack of time, but there seems to be a majority of the committee (if not truly a consensus) in favor of adding garbage collection to C++.

Globally, reference counting is a poor substitute for true garbage collection: it's expensive in terms of run time, and it needs special code to handle cycles. It's applicable in specific limited cases, however, and C++ offers it via std::shared_ptr, at the request of the programmer, when he knows it's applicable.

James Kanze
  • 142,482
  • 15
  • 169
  • 310
  • My understanding is that the people at Apple weren't thrilled with the GC performance (hence, its absence on iOS), but realized that if they knew enough to perform garbage collection at run time, that they could implement similar logic at compile time and obviate the need for GC. ARC resulted from that shift. – Clay Dec 20 '12 at 17:31
  • @Clay I don't know about that; I've never worked at Apple. But depending on what the program is doing, GC can outperform manual memory management; in other cases, it gives a significant appearence of better performance, because the runtime costs can be scheduled to occur when the program isn't doing anything else. – James Kanze Dec 21 '12 at 08:51
  • @JamesKanze One of the rare case is soft-realtime interactive animation. If you want constant 60fps, you need to control CPU load for each frame. Trivial GC implementation defers load to a specific time point, and this make GC impossible to be used on those kind of application. This is especially more important on user devices which can't be scaled over multiple machines. And demand for 60fps is a lot more trivial unlike trivial engineers expect. – eonil Jan 24 '13 at 14:08
  • Incremental GC can make this a little better by trying to distribute load over time instead of deferring it, but you still absent control, and the load is unpredictable. So spikes may happen eventually. (it mostly happens) Real-time GC may solve this problem theoretically, but nothing is well known and proven. And also, still unpredictable. And I don't think realtime GC will perform better than RC. – eonil Jan 24 '13 at 14:14
  • @Eonil Actually, I think interactive animation is a case where garbage collection would shine. You trigger the collector once you've finiehed each frame, under optimal conditions (that's when you have the least number of active pointers); the total time it takes will be less than the time required for freeing memory otherwise. (Of course, depending on the actual allocation patterns, there may be solutions which are superior to both garbage collection and classical malloc/free.) – James Kanze Jan 24 '13 at 17:25
  • If I can get the control for GC, it would be great. But I think it makes sense only when accurate full GC operation doesn't bring huge performance degrade. Because if it's not full or accurate, you can't avoid eventual spike. So you're missing heap lookup cost. GC's alloc/free cost is a lot cheaper but they need live object lookup cost which becomes larger as amount of state getting larger. But definition of interactivity needs maintaining huge amount of states. Still I don't see any proof that GC suits to interactive applications. – eonil Jan 26 '13 at 09:51
  • But maybe in case of very pure functional approach, maybe it would fit. If you fully dispose all the previous state set and creates completely new state set, maybe GC would be great. If GC can detect what to dispose and what to create wisely, maybe it great. But I don't think C++ is pure enough for that. – eonil Jan 26 '13 at 09:57
  • @Eonil I've never seen a garbage collection for C++ which you couldn't manually trigger. Which means that you control when the spike occurs (unlike reference counting, when they can occur at any time). And if you can easily identify the moment when there are very few live objects (which is your case), you're almost guaranteed that GC will require significantly less total time than manual management or reference counting. – James Kanze Jan 26 '13 at 14:20
  • @Eonil What I don't see is interactivity requiring large amounts of state; I would expect just the opposite. If the amount of state which persists is significantly larger than the amount of state whose lifetime is limited to the calculation of a single frame, then GC will not be as good a choice. (Intuitively, I wouldn't expect this, but if you can arrange for most of the short lived state to be on the stack, it comes out to the same thing.) Anyway, short of actual measurements, we can only speculate. – James Kanze Jan 26 '13 at 14:24
  • I agree to my or our opinions can speculate only. Anyway if I can control the GC operation from every aspects, it could be different a lot with what I knew. (I am sorry for my impatient generalization) If it can be deterministic and controllable, I think there's no reason to avoid GC. – eonil Jan 26 '13 at 15:44
2

Take a look of Qt. Qt has implemented this feature by leverage the hierarchy chain. You can new a pointer and assign a parent to it, Qt will help you to manage the memory.

Hang
  • 449
  • 1
  • 4
  • 18
2
  1. There are already some implementations of similar technologies for C++; e.g., Boehm-Demers-Weiser garbage collector.
  2. C++11 has a special Application Binary Interface for anyone wishing to add her own garbage collection.
  3. In the vast majority of cases, techniques like smart pointers can do the job of painless memory management for C++ developers.
FireAphis
  • 6,185
  • 7
  • 38
  • 60
  • Re 3: I'd say that in the vast majority of cases, there isn't any real memory management problem to solve. C++ has value semantics, which means that dynamic allocation is used either for entity objects with externally specified lifetimes (in which case, when to call `delete` is specified by the requirements, and you can't use any sort of reference counting), or to implement dynamically sized structures (like `std::vector`), in which case, the data structure has its own destructor, which can take care of freeing memory. – James Kanze Mar 16 '12 at 08:45
  • @JamesKanze Yes and no. Not all smart pointers have a notion of reference counting and most have methods that release their resource on request; e.g. `shared_ptr::reset`. I'd use a smart pointer, like `scoper_ptr` even in an objects with, as you said, "externally specified lifetime", and just call `reset` if I was asked to release the memory. – FireAphis Mar 16 '12 at 08:51
  • When "initializing" an entity object (in the larger sense), it may be necessary to keep it in a `auto_ptr` until the initialization has finished, and the object is able to take on it's full responsibilities (typically, registering itself for various types of notifications and events). This is only necessary if the object can't be fully initialized in the constructor, however, which isn't the case that often. (In a lot of cases, I'll just do `new`, ignoring the pointer it returns.) – James Kanze Mar 16 '12 at 10:12
0

Microsoft C++/CX has ARC for ref classes. Embarcadero has 2 C++ compilers, one of them has ARC.

OCTAGRAM
  • 570
  • 5
  • 12