Revision as of 10:15, 18 May 2015 editPacerier (talk | contribs)1,866 edits →C++ smart pointers← Previous edit | Latest revision as of 23:23, 3 June 2024 edit undoPanamitsu (talk | contribs)Autopatrolled, Extended confirmed users85,148 edits added Category:Pointers (computer programming) using HotCat | ||
(69 intermediate revisions by 47 users not shown) | |||
Line 1: | Line 1: | ||
{{short description|Data type simulating a pointer with additional features}} | |||
In computer science, a '''smart pointer''' is an ] that simulates a ] while providing additional features, such as automatic ] or ]. These additional features are intended to reduce bugs caused by the misuse of pointers while retaining efficiency. Smart pointers typically keep track of the memory they point to. They may also be used to manage other resources, such as network connections and file handles. | |||
{{more citations needed|date=June 2015}} | |||
{{use dmy dates|date=July 2022|cs1-dates=y}} | |||
{{use list-defined references|date=July 2022}} | |||
In ], a '''smart pointer''' is an ] that simulates a ] while providing added features, such as automatic ] or ]. Such features are intended to reduce ] caused by the misuse of pointers, while retaining efficiency. Smart pointers typically keep track of the memory they point to, and may also be used to manage other resources, such as network connections and ]s. Smart pointers were first popularized in the programming language ] during the first half of the 1990s as rebuttal to criticisms of C++'s lack of ].<ref name="Kline_1997"/><ref name="Colvin_1994"/> | |||
Misuse of pointers is a major source of bugs.{{Citation needed|date=April 2015}} Smart pointers prevent most situations of ]s by making the memory deallocation automatic. More generally, they make ] automatic: the object controlled by a smart pointer is automatically destroyed (] and then deallocated) when the last (or only) owner of the object is destroyed, for example because the owner is a local variable, and execution leaves the variable's ]. Smart pointers also eliminate ]s by postponing destruction until the object is no longer in use. | |||
Pointer misuse can be a major source of bugs. Smart pointers prevent most situations of ]s by making the memory deallocation automatic. More generally, they make ] automatic: an object controlled by a smart pointer is automatically destroyed (] and then deallocated) when the last (or only) owner of an object is destroyed, for example because the owner is a ], and execution leaves the variable's ]. Smart pointers also eliminate ]s by postponing destruction until an object is no longer in use. | |||
Several types of smart pointers exist. Some work with ], others by assigning ownership of the object to a single pointer. If a language supports automatic garbage collection (for instance, ] or ]), then smart pointers are not needed for the reclamation and safety aspects of memory management, but are nevertheless useful for other purposes, such as ] data structure residence management and ] of objects such as ]s or ]s. | |||
If a language supports automatic garbage collection (for example, ] or ]), then smart pointers are unneeded for reclaiming and safety aspects of memory management, yet are useful for other purposes, such as ] data structure residence management and ] of objects such as file handles or ]s. | |||
== C++ smart pointers == | |||
Several types of smart pointers exist. Some work with ], others by assigning ownership of an object to one pointer. | |||
== History == | |||
Even though C++ popularized the concept of smart pointers, especially the ] variety,<ref name="Klabnik-Nichols_2023"/> the immediate predecessor of one of the languages that inspired C++'s design had reference-counted references built into the language. C++ was inspired in part by ].<ref name="Stroustrup"/> Simula67's ancestor was ]. Insofar as Simula I's ''element'' is analogous to C++'s pointer without ''null'', and insofar as Simula I's process with a dummy-statement as its activity body is analogous to C++'s ''struct'' (which itself is analogous to ]'s ''record'' in then-contemporary 1960s work), Simula I had reference counted elements (i.e., pointer-expressions that house indirection) to processes (i.e., records) no later than September 1965, as shown in the quoted paragraphs below.<ref name="Dahl-Nygaard_1966"/> | |||
<blockquote> | |||
Processes can be referenced individually. Physically, a process reference is a pointer to an area of memory containing the data local to the process and some additional information defining its current state of execution. However, for reasons stated in the Section 2.2 process references are always indirect, through items called ''elements.'' Formally a reference to a process is the value of an expression of type ''element''.<br> | |||
…<br> | |||
''element'' values can be stored and retrieved by assignments and references to ''element'' variables and by other means.<br> | |||
The language contains a mechanism for making the attributes of a process accessible from the outside, i.e., from within other processes. This is called remote access- ing. A process is thus a referenceable data structure.<br> | |||
It is worth noticing the similarity between a process whose activity body is a dummy statement, and the record concept recently proposed by C. A. R. Hoare and ]</blockquote> | |||
Because C++ borrowed ]'s approach to memory allocation{{Em dash}}the ''new'' keyword when allocating a process/record to obtain a fresh ''element'' to that process/record{{Em dash}}it is not surprising that C++ eventually resurrected Simula's reference-counted smart-pointer mechanism within ''element'' as well. | |||
== Features == | |||
In ], a smart pointer is implemented as a template class that mimics, by means of ], the behaviors of a traditional ], (e.g. dereferencing, assignment) while providing additional memory management features. | In ], a smart pointer is implemented as a template class that mimics, by means of ], the behaviors of a traditional ], (e.g. dereferencing, assignment) while providing additional memory management features. | ||
Smart pointers can facilitate ] by expressing in the type |
Smart pointers can facilitate ] by expressing, in the type, how the memory of the referent of the pointer will be managed. For example, if a C++ function returns a pointer, there is no way to know whether the caller should delete the memory of the referent when the caller is finished with the information. | ||
<source lang=cpp> | |||
some_type* ambiguous_function(); // What should be done with the result? | |||
</source> | |||
Traditionally, {{citation needed span|text=comments have been used to resolve the ambiguity}}, which is an error-prone, labor-intensive approach. C++11 introduced a way to ensure correct memory management in this case by declaring the function to return a <code>]</code>, | |||
<source lang=cpp> | |||
unique_ptr<some_type> obvious_function1(); | |||
</source> | |||
The declaration of the function return type as a unique_ptr makes explicit the fact that the caller takes ownership of the result, and the C++ runtime ensures that the memory for *some_type will be reclaimed automatically. Prior to ], unique_ptr can be replaced with ]. | |||
<syntaxhighlight lang="cpp"> | |||
=== Creating new objects === | |||
SomeType* AmbiguousFunction(); // What should be done with the result? | |||
</syntaxhighlight> | |||
Traditionally, naming conventions have been used to resolve the ambiguity,<ref name="Taligent"/> which is an error-prone, labor-intensive approach. ] introduced a way to ensure correct memory management in this case by declaring the function to return a <code>unique_ptr</code>, | |||
To ease the allocation of a <source lang="cpp">std::shared_ptr<some_type></source>] introduced: | |||
<source lang="cpp"> | |||
auto s = std::make_shared<some_type>(constructor, parameters, here); | |||
</source> | |||
and similarly <source lang="cpp">std::unique_ptr<some_type></source>Since ] one can use: | |||
<source lang="cpp"> | |||
auto u = std::make_unique<some_type>(constructor, parameters, here); | |||
</source> | |||
It is preferred, in almost all circumstances, to use these facilities over the <code>new</code> keyword:<ref name=isocpp>{{cite web|last=Sutter|first=Herb|authorlink=Herb Sutter|title=Trip Report: ISO C++ Spring 2013 Meeting|url=http://isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting|date=20 April 2013|website=isocpp.org|accessdate=14 June 2013}}</ref> | |||
<syntaxhighlight lang="cpp"> | |||
=== unique_ptr === | |||
std::unique_ptr<SomeType> ObviousFunction(); | |||
</syntaxhighlight> | |||
The declaration of the function return type as a <code>unique_ptr</code> makes explicit the fact that the caller takes ownership of the result, and the C++ runtime ensures that the memory will be reclaimed automatically. Before ], unique_ptr can be replaced with ], which is now deprecated. | |||
] introduces {{code|std::unique_ptr}}, defined in the header {{code|<memory>}}.<ref name="ISO 14882:2011 20.7.1">ISO 14882:2011 20.7.1</ref> | |||
== Creating new objects == | |||
To ease the allocation of a <syntaxhighlight lang="cpp">std::shared_ptr<SomeType></syntaxhighlight>] introduced: | |||
<syntaxhighlight lang="cpp"> | |||
auto s = std::make_shared<SomeType>(constructor, parameters, here); | |||
</syntaxhighlight> | |||
and similarly <syntaxhighlight lang="cpp">std::unique_ptr<some_type></syntaxhighlight>Since ] one can use: | |||
<syntaxhighlight lang="cpp"> | |||
auto u = std::make_unique<SomeType>(constructor, parameters, here); | |||
</syntaxhighlight> | |||
It is preferred, in almost all circumstances, to use these facilities over the <code>new</code> keyword.<ref name="Sutter_2013"/> | |||
== unique_ptr == | |||
] introduces {{code|std::unique_ptr}}, defined in the header {{code|<memory>}}.<ref name="ISO14882_2011"/> | |||
A {{code|unique_ptr}} is a container for a raw pointer, which the <code>unique_ptr</code> is said to own. A <code>unique_ptr</code> explicitly prevents copying of its contained pointer (as would happen with normal assignment), but the {{code|std::move}} function can be used to transfer ownership of the contained pointer to another {{code|unique_ptr}}. A <code>unique_ptr</code> cannot be copied because its copy constructor and assignment operators are explicitly deleted. | A {{code|unique_ptr}} is a container for a raw pointer, which the <code>unique_ptr</code> is said to own. A <code>unique_ptr</code> explicitly prevents copying of its contained pointer (as would happen with normal assignment), but the {{code|std::move}} function can be used to transfer ownership of the contained pointer to another {{code|unique_ptr}}. A <code>unique_ptr</code> cannot be copied because its copy constructor and assignment operators are explicitly deleted. | ||
< |
<syntaxhighlight lang="cpp"> | ||
std::unique_ptr<int> p1(new int(5)); | std::unique_ptr<int> p1(new int(5)); | ||
std::unique_ptr<int> p2 = p1; //Compile error. | std::unique_ptr<int> p2 = p1; // Compile error. | ||
std::unique_ptr<int> p3 = std::move(p1); //Transfers ownership. p3 now owns the memory and p1 is |
std::unique_ptr<int> p3 = std::move(p1); // Transfers ownership. p3 now owns the memory and p1 is set to nullptr. | ||
p3.reset(); //Deletes the memory. | p3.reset(); // Deletes the memory. | ||
p1.reset(); //Does nothing. | p1.reset(); // Does nothing. | ||
</syntaxhighlight> | |||
</source> | |||
<code>std::]</code> is ] under C++11 and completely removed from ]. The copy constructor and assignment operators of {{code|auto_ptr}} do not actually copy the stored pointer. Instead, they ], leaving the prior {{code|auto_ptr}} object empty. This was one way to implement strict ownership, so that only one {{code|auto_ptr}} object can own the pointer at any given time. This means that {{code|auto_ptr}} should not be used where copy semantics are needed.<ref name="CERT"/>{{citation needed|date=September 2016}} Since {{code|auto_ptr}} already existed with its copy semantics, it could not be upgraded to be a move-only pointer without breaking ] with existing code. | |||
==== History ==== | |||
{{code|std::auto_ptr}} is still available, but it is ] under C++11. The copy constructor and assignment operators of {{code|auto_ptr}} do not actually copy the stored pointer. Instead, they ], leaving the previous {{code|auto_ptr}} object empty. This was one way to implement strict ownership, so that only one {{code|auto_ptr}} object could own the pointer at any given time. This means that {{code|auto_ptr}} should not be used where copy semantics are needed.<ref>] | |||
</ref> Since {{code|auto_ptr}} already existed with its copy semantics, it could not be upgraded to be a move-only pointer without breaking ] with existing code | |||
== shared_ptr and weak_ptr == | |||
C++11 introduces {{code|std::shared_ptr}} and {{code|std::weak_ptr}}, defined in the header {{code|<memory>}}.<ref name="ISO14882_2011"/> C++11 also introduces {{Code|std::make_shared}} ({{Code|std::make_unique}} was introduced in C++14) to safely allocate dynamic memory in the ] paradigm.<ref name="ISO14882_2014"/> | |||
A {{code|shared_ptr}} is a container for a ]. It maintains ] ownership of its contained pointer in cooperation with all copies of the {{code|shared_ptr}}. An object referenced by the contained raw pointer will be destroyed when and only when all copies of the {{code|shared_ptr}} have been destroyed. | |||
C++11 introduces {{code|std::shared_ptr}} and {{code|std::weak_ptr}}, defined in the header {{code|<memory>}}.<ref name="ISO 14882:2011 20.7.1"/> | |||
<syntaxhighlight lang="cpp"> | |||
A {{code|shared_ptr}} is a container for a raw pointer. It maintains ] ownership of its contained pointer in cooperation with all copies of the {{code|shared_ptr}}. The object referenced by the contained raw pointer will be destroyed when and only when all copies of the {{code|shared_ptr}} have been destroyed. | |||
std::shared_ptr<int> p0(new int(5)); // Valid, allocates 1 integer and initialize it with value 5. | |||
std::shared_ptr<int> p1(new int); // Valid, allocates 5 integers. | |||
std::shared_ptr<int> p2 = p1; // Both now own the memory. | |||
p1.reset(); // Memory still exists, due to p2. | |||
<source lang="cpp"> | |||
p2.reset(); // Frees the memory, since no one else owns the memory. | |||
std::shared_ptr<int> p1(new int(5)); | |||
</syntaxhighlight> | |||
std::shared_ptr<int> p2 = p1; //Both now own the memory. | |||
p1.reset(); //Memory still exists, due to p2. | |||
p2.reset(); //Deletes the memory, since no one else owns the memory. | |||
</source> | |||
A {{code|weak_ptr}} is a container for a raw pointer. It is created as a copy of a <code>shared_ptr</code>. The existence or destruction of {{code|weak_ptr}} copies of a <code>shared_ptr</code> have no effect on the <code>shared_ptr</code> or its other copies. After all copies of a <code>shared_ptr</code> have been destroyed, all <code>weak_ptr</code> copies become empty. | A {{code|weak_ptr}} is a container for a raw pointer. It is created as a copy of a <code>shared_ptr</code>. The existence or destruction of {{code|weak_ptr}} copies of a <code>shared_ptr</code> have no effect on the <code>shared_ptr</code> or its other copies. After all copies of a <code>shared_ptr</code> have been destroyed, all <code>weak_ptr</code> copies become empty. | ||
< |
<syntaxhighlight lang="cpp"> | ||
std::shared_ptr<int> p1 |
std::shared_ptr<int> p1 = std::make_shared<int>(5); | ||
std::weak_ptr<int> wp1 |
std::weak_ptr<int> wp1 {p1}; // p1 owns the memory. | ||
{ | { | ||
std::shared_ptr<int> p2 = wp1.lock(); //Now p1 and p2 own the memory. | std::shared_ptr<int> p2 = wp1.lock(); // Now p1 and p2 own the memory. | ||
|
// p2 is initialized from a weak pointer, so you have to check if the | ||
// memory still exists! | |||
|
if (p2) { | ||
|
DoSomethingWith(p2); | ||
} | } | ||
} | |||
} //p2 is destroyed. Memory is owned by p1. | |||
// p2 is destroyed. Memory is owned by p1. | |||
p1.reset(); // |
p1.reset(); // Free the memory. | ||
std::shared_ptr<int> p3 = wp1.lock(); //Memory is gone, so we get an empty shared_ptr. | std::shared_ptr<int> p3 = wp1.lock(); | ||
// Memory is gone, so we get an empty shared_ptr. | |||
if (p3) { // code will not execute | |||
if(p3) | |||
ActionThatNeedsALivePointer(p3); | |||
{ | |||
//Will not execute this. | |||
} | } | ||
</syntaxhighlight> | |||
</source> | |||
Because the implementation of {{code|shared_ptr}} uses ], ] are potentially a problem. A circular <code>shared_ptr</code> chain can be broken by changing the code so that one of the references is a <code>weak_ptr</code>. | |||
==== Circular references ==== | |||
Because the implementation of {{code|shared_ptr}} uses ], ]<nowiki/> are potentially a problem. A circular <code>shared_ptr</code> chain can be broken by changing the code so that one of the references is a <code>weak_ptr</code>. | |||
Multiple threads can safely simultaneously access different {{code|shared_ptr}} and {{code|weak_ptr}} objects that point to the same object.<ref name="Boost"/> | |||
==== Concurrency guarantees ==== | |||
Multiple threads can safely simultaneously access different {{code|shared_ptr}} and {{code|weak_ptr}} objects that point to the same object.<ref> (does not formally cover std::shared_ptr, but is believed to have the same threading limitations)</ref> | |||
The referenced object |
The referenced object must be protected separately to ensure ]. | ||
{{code|shared_ptr}} and {{code|weak_ptr}} are based on versions used by the ].{{citation needed|date=January 2014}} ] (TR1) first introduced them to the standard, as ], but C++11 adds more functions, in line with the Boost version. | |||
==== History ==== | |||
{{code|shared_ptr}} and {{code|weak_ptr}} are based on versions used by the ].{{citation needed|date = January 2014}} ] first introduced them to the standard, but C++11 gives them additional functionality in line with the Boost version. | |||
== Other types of smart pointers == | |||
There are other types of smart pointers (which are not in the C++ standard) implemented on popular C++ libraries or custom ], some examples include ]<ref>{{cite web|url=https://github.com/facebook/folly/blob/main/folly/synchronization/Hazptr.h|title=folly/Hazptr.h at main · facebook/folly|website=github.com}}</ref> and intrusive pointer.<ref>{{cite web|url=https://www.boost.org/doc/libs/1_81_0/libs/smart_ptr/doc/html/smart_ptr.html|title=Boost.SmartPtr: The Smart Pointer Library - 1.81.0|website=boost.org}}</ref> <ref>{{cite web|url=https://github.com/electronicarts/EASTL/blob/master/include/EASTL/intrusive_ptr.h|title=EASTL/intrusive_ptr.h at master · electronicarts/EASTL|website=github.com}}</ref> | |||
== See also == | == See also == | ||
* ] (RAII) | |||
* ] | * ] | ||
* ] | |||
* ] | |||
* ] | * ] | ||
* ] | * ] | ||
* ] | |||
* The ] includes boost::intrusive_ptr,<ref>http://www.boost.org/doc/libs/1_52_0/libs/smart_ptr/intrusive_ptr.html</ref> a reference-counting and intrusively counted smart pointer implementation for C++. | |||
* ] | |||
* ] (RAII) | |||
* ] in computer programming | |||
== References == | == References == | ||
{{Reflist|refs= | |||
<references /> | |||
<ref name="Kline_1997">{{cite web |url=http://www.cis.usouthal.edu/faculty/drh/c%2B%2Bfaq/freestore-mgmt.html#[16.20 |title=C++ FAQs Lite's sections on reference-counted smart pointers and copy-on-write reference semantics in the freestore management FAQs |author-last=Kline |author-first=Marshall |date=September 1997 |website=cis.usouthal.edu |access-date=2018-04-06}}</ref> | |||
<ref name="Colvin_1994">{{cite web |url=http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1994/N0555.pdf |title=proposal to standardize counted_ptr in the C++ standard library |author-last=Colvin |author-first=Gregory |date=1994 |website=open-std.org |access-date=2018-04-06}}</ref> | |||
<ref name="Stroustrup">{{cite web |url=http://www.stroustrup.com/hopl2.pdf |author-last=Stroustrup |author-first=Bjarne |title=A history of C++: 1979–1991 |access-date=2018-04-06}}</ref> | |||
<ref name="Dahl-Nygaard_1966">{{cite web |url=http://folk.uio.no/simula67/Archive/artikkel1966cacm.pdf |author-last1=Dahl |author-first1=Ole-Johan |author-last2=Nygaard |author-first2=Kristen |title=SIMULA—An ALGOL-based simulation language |date=September 1966 |website=folk.uio.no |access-date=2018-04-06}}</ref> | |||
<ref name="Taligent">{{cite web |url=https://root.cern.ch/TaligentDocs/TaligentOnline/DocumentRoot/1.0/Docs/books/WM/WM_67.html#HEADING81 |title=Taligent's Guide to Designing Programs, section Use special names for copy, create, and adopt routines}}</ref> | |||
<ref name="Sutter_2013">{{cite web |author-last=Sutter |author-first=Herb |author-link=Herb Sutter |title=Trip Report: ISO C++ Spring 2013 Meeting |url=http://isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting |date=2013-04-20 |website=isocpp.org |access-date=2013-06-14}}</ref> | |||
<ref name="ISO14882_2011">ISO 14882:2011 20.7.1</ref> | |||
<ref name="CERT">CERT C++ Secure Coding Standard</ref> | |||
<ref name="ISO14882_2014">ISO 14882:2014 20.7.1</ref> | |||
<ref name="Boost">{{cite web |url=http://www.boost.org/libs/smart_ptr/shared_ptr.htm#ThreadSafety |title=boost::shared_ptr thread safety}} (NB. Does not formally cover std::shared_ptr, but is believed to have the same threading limitations.)</ref> | |||
<ref name="Klabnik-Nichols_2023">{{cite book |title=The Rust Programming Language |chapter=15. Smart Pointers |date=2023 |orig-date=2018<!-- 1st edition --> |edition=2 |author-first1=Steve |author-last1=Klabnik |author-first2=Carol |author-last2=Nichols |publisher=] |publication-place=San Francisco, California, USA |isbn=978-1-7185-0310-6 <!-- |lccn=1st edition: 2018014097 --> |pages=315–351 }} (xxix+1+527+3 pages)</ref> | |||
}} | |||
== Further reading == | |||
* {{cite book |title=Effective Modern C++ |author-first=Scott |author-last=Meyers |author-link=Scott Meyers |publisher=] |date=2014 |isbn=978-1-49190399-5 |location=Sebastopol, California, USA |oclc=884480640}} | |||
* {{cite book |chapter-url=http://www.informit.com/articles/article.aspx?p=25264 |chapter=Smart Pointers |title=Modern C++ Design - Generic Programming and Design Patterns Applied |title-link=Modern C++ Design |author-first=Andrei |author-last=Alexandrescu |author-link=Andrei Alexandrescu |publisher=] |date=2001}} | |||
* {{cite web |url=http://www.drdobbs.com/184403837/ |title=The New C++: Smart(er) Pointers |author-first=Herb |author-last=Sutter |author-link=Herb Sutter |date=2002-08-01}} | |||
* . Yonat Sharon | |||
* . John M. Dlugosz | |||
==External links== | == External links == | ||
* . '''' by Nicolai M. Josuttis | |||
*Sample chapter "" from the book '']'' by ], Addison-Wesley, 2001. | |||
* | |||
*Code example "" from the book '''' by ] | |||
*"" | |||
*Article "" by ] August 1, 2002 | |||
*"" by ] | |||
*"" by ] | |||
* The Yet Another Smart Pointer implementation in C++ | |||
* | * | ||
* | * | ||
* | |||
] | ] | ||
] | ] | ||
] |
Latest revision as of 23:23, 3 June 2024
Data type simulating a pointer with additional featuresThis article needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed. Find sources: "Smart pointer" – news · newspapers · books · scholar · JSTOR (June 2015) (Learn how and when to remove this message) |
In computer science, a smart pointer is an abstract data type that simulates a pointer while providing added features, such as automatic memory management or bounds checking. Such features are intended to reduce bugs caused by the misuse of pointers, while retaining efficiency. Smart pointers typically keep track of the memory they point to, and may also be used to manage other resources, such as network connections and file handles. Smart pointers were first popularized in the programming language C++ during the first half of the 1990s as rebuttal to criticisms of C++'s lack of automatic garbage collection.
Pointer misuse can be a major source of bugs. Smart pointers prevent most situations of memory leaks by making the memory deallocation automatic. More generally, they make object destruction automatic: an object controlled by a smart pointer is automatically destroyed (finalized and then deallocated) when the last (or only) owner of an object is destroyed, for example because the owner is a local variable, and execution leaves the variable's scope. Smart pointers also eliminate dangling pointers by postponing destruction until an object is no longer in use.
If a language supports automatic garbage collection (for example, Java or C#), then smart pointers are unneeded for reclaiming and safety aspects of memory management, yet are useful for other purposes, such as cache data structure residence management and resource management of objects such as file handles or network sockets.
Several types of smart pointers exist. Some work with reference counting, others by assigning ownership of an object to one pointer.
History
Even though C++ popularized the concept of smart pointers, especially the reference-counted variety, the immediate predecessor of one of the languages that inspired C++'s design had reference-counted references built into the language. C++ was inspired in part by Simula67. Simula67's ancestor was Simula I. Insofar as Simula I's element is analogous to C++'s pointer without null, and insofar as Simula I's process with a dummy-statement as its activity body is analogous to C++'s struct (which itself is analogous to C. A. R. Hoare's record in then-contemporary 1960s work), Simula I had reference counted elements (i.e., pointer-expressions that house indirection) to processes (i.e., records) no later than September 1965, as shown in the quoted paragraphs below.
Processes can be referenced individually. Physically, a process reference is a pointer to an area of memory containing the data local to the process and some additional information defining its current state of execution. However, for reasons stated in the Section 2.2 process references are always indirect, through items called elements. Formally a reference to a process is the value of an expression of type element.
…
element values can be stored and retrieved by assignments and references to element variables and by other means.
The language contains a mechanism for making the attributes of a process accessible from the outside, i.e., from within other processes. This is called remote access- ing. A process is thus a referenceable data structure.
It is worth noticing the similarity between a process whose activity body is a dummy statement, and the record concept recently proposed by C. A. R. Hoare and N. Wirth
Because C++ borrowed Simula's approach to memory allocation—the new keyword when allocating a process/record to obtain a fresh element to that process/record—it is not surprising that C++ eventually resurrected Simula's reference-counted smart-pointer mechanism within element as well.
Features
In C++, a smart pointer is implemented as a template class that mimics, by means of operator overloading, the behaviors of a traditional (raw) pointer, (e.g. dereferencing, assignment) while providing additional memory management features.
Smart pointers can facilitate intentional programming by expressing, in the type, how the memory of the referent of the pointer will be managed. For example, if a C++ function returns a pointer, there is no way to know whether the caller should delete the memory of the referent when the caller is finished with the information.
SomeType* AmbiguousFunction(); // What should be done with the result?
Traditionally, naming conventions have been used to resolve the ambiguity, which is an error-prone, labor-intensive approach. C++11 introduced a way to ensure correct memory management in this case by declaring the function to return a unique_ptr
,
std::unique_ptr<SomeType> ObviousFunction();
The declaration of the function return type as a unique_ptr
makes explicit the fact that the caller takes ownership of the result, and the C++ runtime ensures that the memory will be reclaimed automatically. Before C++11, unique_ptr can be replaced with auto_ptr, which is now deprecated.
Creating new objects
To ease the allocation of a
std::shared_ptr<SomeType>
C++11 introduced:
auto s = std::make_shared<SomeType>(constructor, parameters, here);
and similarly
std::unique_ptr<some_type>
Since C++14 one can use:
auto u = std::make_unique<SomeType>(constructor, parameters, here);
It is preferred, in almost all circumstances, to use these facilities over the new
keyword.
unique_ptr
C++11 introduces std::unique_ptr
, defined in the header <memory>
.
A unique_ptr
is a container for a raw pointer, which the unique_ptr
is said to own. A unique_ptr
explicitly prevents copying of its contained pointer (as would happen with normal assignment), but the std::move
function can be used to transfer ownership of the contained pointer to another unique_ptr
. A unique_ptr
cannot be copied because its copy constructor and assignment operators are explicitly deleted.
std::unique_ptr<int> p1(new int(5)); std::unique_ptr<int> p2 = p1; // Compile error. std::unique_ptr<int> p3 = std::move(p1); // Transfers ownership. p3 now owns the memory and p1 is set to nullptr. p3.reset(); // Deletes the memory. p1.reset(); // Does nothing.
std::auto_ptr
is deprecated under C++11 and completely removed from C++17. The copy constructor and assignment operators of auto_ptr
do not actually copy the stored pointer. Instead, they transfer it, leaving the prior auto_ptr
object empty. This was one way to implement strict ownership, so that only one auto_ptr
object can own the pointer at any given time. This means that auto_ptr
should not be used where copy semantics are needed. Since auto_ptr
already existed with its copy semantics, it could not be upgraded to be a move-only pointer without breaking backward compatibility with existing code.
shared_ptr and weak_ptr
C++11 introduces std::shared_ptr
and std::weak_ptr
, defined in the header <memory>
. C++11 also introduces std::make_shared
(std::make_unique
was introduced in C++14) to safely allocate dynamic memory in the RAII paradigm.
A shared_ptr
is a container for a raw pointer. It maintains reference counting ownership of its contained pointer in cooperation with all copies of the shared_ptr
. An object referenced by the contained raw pointer will be destroyed when and only when all copies of the shared_ptr
have been destroyed.
std::shared_ptr<int> p0(new int(5)); // Valid, allocates 1 integer and initialize it with value 5. std::shared_ptr<int> p1(new int); // Valid, allocates 5 integers. std::shared_ptr<int> p2 = p1; // Both now own the memory. p1.reset(); // Memory still exists, due to p2. p2.reset(); // Frees the memory, since no one else owns the memory.
A weak_ptr
is a container for a raw pointer. It is created as a copy of a shared_ptr
. The existence or destruction of weak_ptr
copies of a shared_ptr
have no effect on the shared_ptr
or its other copies. After all copies of a shared_ptr
have been destroyed, all weak_ptr
copies become empty.
std::shared_ptr<int> p1 = std::make_shared<int>(5); std::weak_ptr<int> wp1 {p1}; // p1 owns the memory. { std::shared_ptr<int> p2 = wp1.lock(); // Now p1 and p2 own the memory. // p2 is initialized from a weak pointer, so you have to check if the // memory still exists! if (p2) { DoSomethingWith(p2); } } // p2 is destroyed. Memory is owned by p1. p1.reset(); // Free the memory. std::shared_ptr<int> p3 = wp1.lock(); // Memory is gone, so we get an empty shared_ptr. if (p3) { // code will not execute ActionThatNeedsALivePointer(p3); }
Because the implementation of shared_ptr
uses reference counting, circular references are potentially a problem. A circular shared_ptr
chain can be broken by changing the code so that one of the references is a weak_ptr
.
Multiple threads can safely simultaneously access different shared_ptr
and weak_ptr
objects that point to the same object.
The referenced object must be protected separately to ensure thread safety.
shared_ptr
and weak_ptr
are based on versions used by the Boost libraries. C++ Technical Report 1 (TR1) first introduced them to the standard, as general utilities, but C++11 adds more functions, in line with the Boost version.
Other types of smart pointers
There are other types of smart pointers (which are not in the C++ standard) implemented on popular C++ libraries or custom STL, some examples include hazard pointer and intrusive pointer.
See also
- auto_ptr
- Fat pointer
- Tagged pointer
- Opaque pointer
- Reference (computer science)
- Boost (C++ libraries)
- Automatic Reference Counting
- Resource acquisition is initialization (RAII)
- Garbage collection in computer programming
References
- Kline, Marshall (September 1997). "C++ FAQs Lite's sections on reference-counted smart pointers and copy-on-write reference semantics in the freestore management FAQs". cis.usouthal.edu. Retrieved 2018-04-06.
- Colvin, Gregory (1994). "proposal to standardize counted_ptr in the C++ standard library" (PDF). open-std.org. Retrieved 2018-04-06.
- Klabnik, Steve; Nichols, Carol (2023) . "15. Smart Pointers". The Rust Programming Language (2 ed.). San Francisco, California, USA: No Starch Press, Inc. pp. 315–351. ISBN 978-1-7185-0310-6. (xxix+1+527+3 pages)
- Stroustrup, Bjarne. "A history of C++: 1979–1991" (PDF). Retrieved 2018-04-06.
- Dahl, Ole-Johan; Nygaard, Kristen (September 1966). "SIMULA—An ALGOL-based simulation language" (PDF). folk.uio.no. Retrieved 2018-04-06.
- "Taligent's Guide to Designing Programs, section Use special names for copy, create, and adopt routines".
- Sutter, Herb (2013-04-20). "Trip Report: ISO C++ Spring 2013 Meeting". isocpp.org. Retrieved 2013-06-14.
- ^ ISO 14882:2011 20.7.1
- CERT C++ Secure Coding Standard
- ISO 14882:2014 20.7.1
- "boost::shared_ptr thread safety". (NB. Does not formally cover std::shared_ptr, but is believed to have the same threading limitations.)
- "folly/Hazptr.h at main · facebook/folly". github.com.
- "Boost.SmartPtr: The Smart Pointer Library - 1.81.0". boost.org.
- "EASTL/intrusive_ptr.h at master · electronicarts/EASTL". github.com.
Further reading
- Meyers, Scott (2014). Effective Modern C++. Sebastopol, California, USA: O'Reilly Media. ISBN 978-1-49190399-5. OCLC 884480640.
- Alexandrescu, Andrei (2001). "Smart Pointers". Modern C++ Design - Generic Programming and Design Patterns Applied. Addison-Wesley.
- Sutter, Herb (2002-08-01). "The New C++: Smart(er) Pointers".
- Smart Pointers - What, Why, Which?. Yonat Sharon
- Smart Pointers Overview. John M. Dlugosz
External links
- countptr.hpp. The C++ Standard Library - A Tutorial and Reference by Nicolai M. Josuttis
- Boost Smart Pointers
- Smart Pointers in Delphi
- Smart Pointers in Rust
- Smart Pointers in Modern C++