Content deleted Content added
Undid revision 934736152 by JeffyTheDragonSlayer (talk) -- interesting. But we'd really need a source for that. See Wikipedia:NOR |
|||
(48 intermediate revisions by 34 users not shown) | |||
Line 1:
{{short description|Approach to 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 6 ⟶ 7:
| last=Stroustrup
| date=2017-09-30
|
RAII is associated most prominently with [[C++]], where it originated, but also [[
| author=Michael Burr▼
| date=2008-09-19▼
| accessdate=2019-03-09}}</ref>▼
Other names for this idiom include ''Constructor Acquires, Destructor Releases'' (CADRe)<ref>{{Cite web
Line 23 ⟶ 18:
| work=ISO C++ Standard - Future Proposals
| publisher=[[Google Groups]]
|
| url=http://allenchou.net/2014/10/scope-based-resource-management-raii/
| title=Scope-Based Resource Management (RAII)
Line 29 ⟶ 24:
| last=Chou
| date=2014-10-01
|
==C++11 example==
The following [[C++11]] example demonstrates usage of RAII for file access and [[mutex]] locking:
<
#include <fstream>
#include <iostream>
Line 57 ⟶ 52:
// |file| will be closed first when leaving scope (regardless of exception)
// |mutex| will be unlocked second (from |lock| destructor) when leaving scope
// (regardless of exception).
}
</syntaxhighlight>
This code is exception-safe because C++ guarantees that all
| url=http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf
| title=Working Draft, Standard for Programming Language C++
| page=151, section §9.6
| access-date=2023-09-07
}}</ref>
The destructors of both the ''lock'' and ''file'' objects are therefore guaranteed to be called when returning from the function, whether an exception has been thrown or not.<ref>{{cite web
| url=https://isocpp.org/wiki/faq/exceptions#dtors-shouldnt-throw
| title=How can I handle a destructor that fails?
| publisher=Standard C++ Foundation
|
Local variables allow easy management of multiple resources within a single function: they are destroyed in the reverse order of their construction, and an object is destroyed only if fully constructed—that is, if no exception propagates from its constructor.<ref>{{cite web
| url=http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf
| title=Working Draft, Standard for
| date=2017-03-21
| author=Richard Smith
|
Using RAII greatly simplifies resource management, reduces overall code size and helps ensure program correctness. RAII is therefore
| url=https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
| title=C++ Core Guidelines
| date=2020-08-03
| last1=Stroustrup
| first1=Bjarne
| author-link1=Bjarne Stroustrup
| last2=Sutter
| first2=Herb
| author-link2=Herb Sutter
and most of the C++ standard library follows the idiom.<ref>{{cite web
| url=https://isocpp.org/wiki/faq/exceptions#too-many-trycatch-blocks
| title=I have too many try blocks; what can I do about it?
| publisher=Standard C++ Foundation
|
==Benefits==
The advantages of RAII as a resource management technique are that it provides encapsulation,
Encapsulation is provided because resource management logic is defined once in the class, not at each call site. Exception safety is provided for stack resources (resources that are released in the same scope as they are acquired) by tying the resource to the lifetime of a stack variable (a local variable declared in a given scope): if an [[Exception handling|exception]] is thrown, and proper exception handling is in place, the only code that will be executed when exiting the current [[Scope (computer science)|scope]] are the destructors of objects declared in that scope. Finally, locality of definition is provided by writing the constructor and destructor definitions next to each other in the class definition.
Line 89 ⟶ 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
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.
Ownership of dynamically allocated objects (memory allocated with <
Also, messages can be sent 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.
Both [[Clang]] and [[GNU Compiler Collection]] implement a non-standard extension to the [[C (programming language)|C]] language to support RAII: the "cleanup" variable attribute.<ref>{{Cite web▼
== Compiler "cleanup" extensions ==
▲Both [[Clang]] and the [[GNU Compiler Collection]] implement a non-standard extension to the [[C (programming language)|C]] language to support RAII: the "cleanup" variable attribute.<ref>{{Cite web
| url=https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
| title=Specifying Attributes of Variables
| work=Using the GNU Compiler Collection (GCC)
| publisher=[[GNU Project]]
|
<syntaxhighlight lang=c>
void example_usage() {
fputs("hello logfile!", logfile);
}
</syntaxhighlight>
In this example, the compiler arranges for the ''fclosep'' function to be called on ''logfile'' before ''example_usage'' returns.
Line 123 ⟶ 135:
RAII only works for resources acquired and released (directly or indirectly) by stack-allocated objects,
where there ''is'' a well-defined static object lifetime.
[[Heap (programming)|Heap]]-allocated objects which themselves acquire and release resources are common in many languages, including C++. RAII depends on heap-based objects to be implicitly or explicitly deleted along all possible execution paths, in order to trigger its resource-releasing destructor (or equivalent).<ref>{{cite news
| title=Exceptional Situations and Program Reliability
| first1=Westley
Line 133 ⟶ 145:
| issue=2
| year=2008
| url=https://web.eecs.umich.edu/~weimerw/p/weimer-toplas2008.pdf}}</ref>{{rp|8:27}} This can be achieved by using [[smart pointer]]s to manage all heap objects, with weak
In C++, stack unwinding is only guaranteed to occur if the exception is caught somewhere. This is because "If no matching handler is found in a program, the function terminate() is called; whether or not the stack is unwound before this call to terminate() is implementation-defined (15.5.1)." (C++03 standard, §15.3/9).<ref>{{cite web
Line 141 ⟶ 153:
| date=2011-04-05
| publisher=Stack Overflow
|
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 149 ⟶ 163:
| work=Extending and Embedding the Python Interpreter
| publisher=[[Python Software Foundation]]
|
| url=https://stackoverflow.com/a/4938780
| title=Does PHP support the RAII pattern? How?
| author=hobbs
| date=2011-02-08
|
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
| url=https://docs.python.org/3/library/gc.html
| title=gc — Garbage Collector interface
| work=The Python Standard Library
| publisher=Python Software Foundation
|
== References ==
Line 174 ⟶ 188:
| last = Stroustrup
| first = Bjarne
|
| year = 1994
| publisher = Addison-Wesley
Line 184 ⟶ 198:
{{wikibooks|More C++ Idioms|Resource Acquisition Is Initialization}}
* Sample Chapter: "[https://www.informit.com/articles/article.aspx?p=30642&seqNum=8 Gotcha #67: Failure to Employ Resource Acquisition Is Initialization]" by Stephen C. Dewhurst
* Interview: "[https://www.artima.com/intv/modern3.html A Conversation with Bjarne Stroustrup]" by Bill Venners
* Article: "[https://www.artima.com/cppsource/bigtwo3.html The Law of The Big Two]" by Bjorn Karlsson and Matthew Wilson
* Article: "[https://web.archive.org/web/20090815095635/http://gethelp.devx.com/techtips/cpp_pro/10min/2001/november/10min1101.asp Implementing the 'Resource Acquisition is Initialization' Idiom]" by Danny Kalev
* Article: "[https://www.codeproject.com/Articles/10141/RAII-Dynamic-Objects-and-Factories-in-C RAII, Dynamic Objects, and Factories in C++]" by Roland Pibinger
* RAII in Delphi: "[http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.html One-liner RAII in Delphi]" by Barry Kelly
* Guide: [https://www.w3computing.com/articles/resource-acquisition-is-initialization-raii-in-cpp/ RAII in C++] by W3computing
{{C++ programming language}}
{{Design Patterns patterns}}
[[Category:Articles with example C++ code]]
[[Category:Object-oriented programming]]
[[Category:Software design patterns]]
[[Category:Programming idioms]]
[[Category:C++]]
|