Resource acquisition is initialization: Difference between revisions

Content deleted Content added
m Add example of using network resources in RAII
 
(11 intermediate revisions by 10 users not shown)
Line 1:
{{short description|ProgrammingApproach idiomto managing resources by tying them to object lifetime}}
{{more citations needed|date=December 2012}}
'''Resource acquisition is initialization''' ('''RAII''')<ref name="faq">{{cite web
Line 7:
| last=Stroustrup
| date=2017-09-30
| access-date=2019-03-09}}</ref> is a [[programming idiom]]<ref>{{cite book |last1=Sutter |first1=Herb |author-link1=Herb Sutter |last2=Alexandrescu |first2=Andrei |author-link2=Andrei Alexandrescu |year=2005 |title=C++ Coding Standards |url=https://archive.org/details/isbn_0321113586 |url-access=limited |series=C++ In-Depth Series |publisher=Addison-Wesley |page=[https://archive.org/details/isbn_0321113586/page/n54 24] |isbn=978-0-321-11358-0 }}</ref> used in several [[Object-oriented programming|object-oriented]], [[Statically-typed programming language|statically typed]] programming languages to describe a particular language behavior. In RAII, holding a resource is a [[class invariant]], and is tied to [[object lifetime]]. [[Resource allocation (computer)|Resource allocation]] (or acquisition) is done during object creation (specifically initialization), by the [[Constructor (object-oriented programming)|constructor]], while resource deallocation (release) is done during object destruction (specifically finalization), by the [[Destructor (computer programming)|destructor]]. In other words, resource acquisition must succeed for initialization to succeed. Thus, the resource is guaranteed to be held between when initialization finishes and finalization starts (holding the resources is a class invariant), and to be held only when the object is alive. Thus, if there are no object leaks, there are no [[resource leak]]s.
 
RAII is associated most prominently with [[C++]], where it originated, but also [[Ada (programming language)|Ada]],<ref>{{cite web |title=Gem #70: The Scope Locks Idiom |url=https://www.adacore.com/gems/gem-70 |website=AdaCore |access-date=21 May 2021 |language=en}}</ref> [[Vala (programming language)|Vala]],<ref>{{cite web |author1=The Valadate Project |title=Destruction |url=https://naaando.gitbooks.io/the-vala-tutorial/content/en/4-object-oriented-programming/destruction.html |website=The Vala Tutorial version 0.30 |access-date=21 May 2021}}</ref> and [[Rust (programming language)|Rust]].<ref>{{Cite web|title=RAII - Rust By Example|url=https://doc.rust-lang.org/rust-by-example/scope/raii.html|access-date=2020-11-22|website=doc.rust-lang.org}}</ref> The technique was developed for [[Exception safety|exception-safe]] [[resource management (computing)|resource management]] in C++{{sfn|Stroustrup|1994|loc=16.5 Resource Management, pp. 388–89}} during 1984–891984–1989, primarily by [[Bjarne Stroustrup]] and [[Andrew Koenig (programmer)|Andrew Koenig]],{{sfn|Stroustrup|1994|loc=16.1 Exception Handling: Introduction, pp. 383–84}} and the term itself was coined by Stroustrup.{{sfn|Stroustrup|1994|p=389|ps=. I called this technique "resource acquisition is initialization."}} RAII is generally pronounced as an [[initialism]], sometimes pronounced as "R, A, double I".<ref>{{cite web
| url=https://stackoverflow.com/a/99986
| title=How do you pronounce RAII?
| author=Michael Burr
| date=2008-09-19
| publisher=[[Stack Overflow]]
| access-date=2019-03-09}}</ref>
 
Other names for this idiom include ''Constructor Acquires, Destructor Releases'' (CADRe)<ref>{{Cite web
Line 30 ⟶ 24:
| last=Chou
| date=2014-10-01
| access-date=2019-03-09}}</ref> This latter term is for the special case of [[automatic variable]]s. RAII ties resources to object ''lifetime,'' which may not coincide with entry and exit of a scope. (Notably variables allocated on the [[Heap (programming)|free store]] have lifetimes unrelated to any given scope.) However, using RAII for automatic variables (SBRM) is the most common use case.
 
==C++11 example==
Line 109 ⟶ 103:
 
Comparing RAII with the <code>finally</code> construct used in Java, Stroustrup wrote that “In realistic systems, there are far more resource acquisitions than kinds of resources, so the 'resource acquisition is initialization' technique leads to less code than use of a 'finally' construct.”<ref name="faq"/>
 
As a class invariant, RAII provides guarantees that an object instance that is supposed to have acquired a resource has in fact done so. This eliminates the need for additional "setup" methods to get a newly-created object into a usable state (all such work is performed in the constructor; similarly, "shutdown" tasks to release resources occur in the object's destructor), and the need to test instances to verify that they have been properly set up before every use.<ref>[https://en.cppreference.com/w/cpp/language/raii.html RAII at cppreference.com]</ref>
 
==Typical uses==
 
The RAII design is often used for controlling mutex locks in [[thread (computing)#Multithreading|multi-threaded]] applications. In that use, the object releases the lock when destroyed. Without RAII in this scenario the potential for [[Deadlock (computer science)|deadlock]] would be high and the logic to lock the mutex would be far from the logic to unlock it. With RAII, the code that locks the mutex essentially includes the logic that the lock will be released when execution leaves the scope of the RAII object.
 
Another typical example is interacting with files: We could have an object that represents a file that is open for writing, wherein the file is opened in the constructor and closed when execution leaves the object's scope. In both cases, RAII ensures only that the resource in question is released appropriately; care must still be taken to maintain exception safety. If the code modifying the data structure or file is not exception-safe, the mutex could be unlocked or the file closed with the data structure or file corrupted.
Line 118 ⟶ 114:
Ownership of dynamically allocated objects (memory allocated with <code>new</code> in C++) can also be controlled with RAII, such that the object is released when the RAII (stack-based) object is destroyed. For this purpose, the C++11 standard library defines the [[smart pointer]] classes <code>[[Smart pointer#unique_ptr|std::unique_ptr]]</code> for single-owned objects and <code>[[Smart_pointer#shared_ptr_and_weak_ptr|std::shared_ptr]]</code> for objects with shared ownership. Similar classes are also available through <code>[[auto ptr|std::auto_ptr]]</code> in C++98, and <code>boost::shared_ptr</code> in the [[Boost (C++ libraries)|Boost libraries]].
 
Also, network resourcesmessages can receivebe messagessent to network resources using RAII. In this case, the RAII object would send a message to a [[Network socket|socket]] at the end of the constructor, when its initialization is completed. It would also send a message at the beginning of the destructor, when the object is about to be destroyed. Such a construct might be used in a client object to establish a connection with a server running in another process.
 
== Compiler "cleanup" extensions ==
Line 158 ⟶ 154:
| publisher=Stack Overflow
| access-date=2019-03-09}}</ref> This behavior is usually acceptable, since the operating system releases remaining resources like memory, files, sockets, etc. at program termination.{{citation needed|date=January 2020}}
 
At the 2018 Gamelab conference, [[Jonathan Blow]] claimed that use of RAII can cause [[Fragmentation (computing)|memory fragmentation]] which in turn can cause [[CPU cache#Cache miss|cache misses]] and a 100 times or worse hit on [[Computer performance|performance]].<ref>{{YouTube |id=uZgbKrDEzAs |t=614 |title=Gamelab2018 - Jon Blow's Design decisions on creating Jai a new language for game programmers}}</ref>
 
== Reference counting ==
Line 172 ⟶ 170:
| access-date=2019-03-09}}</ref> manage object lifetime by [[reference counting]], which makes it possible to use RAII. Objects that are no longer referenced are immediately destroyed or finalized and released, so a destructor or [[finalizer]] can release the resource at that time. However, it is not always idiomatic in such languages, and is specifically discouraged in Python (in favor of [[context manager]]s and ''finalizers'' from the ''weakref'' package).{{fact|date=June 2022}}
 
However, object lifetimes are not necessarily bound to any scope, and objects may be destroyed non-deterministically or not at all. This makes it possible to accidentally leak resources that should have been released at the end of some scope. Objects stored in a [[static variable]] (notably a [[global variable]]) may not be finalized when the program terminates, so their resources are not released; CPython makes no guarantee of finalizing such objects, for instance. Further, objects with [[circular referencesreference]]s will not be collected by a simple reference counter, and will live indeterminately long; even if collected (by more sophisticated garbage collection), destruction time and destruction order will be non-deterministic. In CPython there is a cycle detector which detects cycles and finalizes the objects in the cycle, though prior to CPython 3.4, cycles are not collected if any object in the cycle has a finalizer.<ref>{{cite web
| url=https://docs.python.org/3/library/gc.html
| title=gc — Garbage Collector interface