182 lines
19 KiB
HTML
182 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
|
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>std::enable_shared_from_this</title>
|
|
<link rel="stylesheet" href="ext.css" />
|
|
<link rel="stylesheet" href="site_modules.css" />
|
|
</head>
|
|
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-cpp_memory_enable_shared_from_this skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading"><span style="font-size:0.7em; line-height:130%">std::</span>enable_shared_from_this</h1>
|
|
<div id="bodyContent">
|
|
<div id="contentSub"><span class="subpages">< <a href="cpp.html">cpp</a>‎ | <a href="cpp-memory.html">memory</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<table class="t-dcl-begin">
|
|
<tbody>
|
|
<tr class="t-dsc-header">
|
|
<td>
|
|
<div>定义于头文件 <code><a href="cpp-header-memory.html"><memory></a></code></div>
|
|
</td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx11">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span><span class="sy1"><</span> <span class="kw1">class</span> T <span class="sy1">></span> <span class="kw1">class</span> enable_shared_from_this<span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p><code>std::enable_shared_from_this</code> 能让其一个对象(假设其名为 <code>t</code> ,且已被一个 <span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> 对象 <code>pt</code> 管理)安全地生成其他额外的 <span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> 实例(假设名为 <code>pt1, pt2, ...</code> ) ,它们与 <code>pt</code> 共享对象 <code>t</code> 的所有权。</p>
|
|
<p>若一个类 <code>T</code> 继承 <code>std::enable_shared_from_this<T></code> ,则会为该类 <code>T</code> 提供成员函数: <code>shared_from_this</code> 。 当 <code>T</code> 类型对象 <code>t</code> 被一个为名为 <code>pt</code> 的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>T<span class="sy1">></span></span></span> 类对象管理时,调用 <code>T::shared_from_this</code> 成员函数,将会返回一个新的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>T<span class="sy1">></span></span></span> 对象,它与 <code>pt</code> 共享 <code>t</code> 的所有权。</p>
|
|
<h3><span class="mw-headline" id=".E6.88.90.E5.91.98.E5.87.BD.E6.95.B0">成员函数</span></h3>
|
|
<table class="t-dsc-begin">
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div t-dsc-member-nobold-div">
|
|
<div><a href="cpp-memory-enable_shared_from_this-enable_shared_from_this.html"><span class="t-lines"><span>(构造函数)</span></span></a></div>
|
|
</div>
|
|
</td>
|
|
<td>构造 <code>enable_shared_from_this</code> 对象<br />
|
|
<span class="t-mark">(受保护成员函数)</span></td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div t-dsc-member-nobold-div">
|
|
<div><a href="cpp-memory-enable_shared_from_this-~enable_shared_from_this.html"><span class="t-lines"><span>(析构函数)</span></span></a></div>
|
|
</div>
|
|
</td>
|
|
<td>销毁 <code>enable_shared_from_this</code> 对象<br />
|
|
<span class="t-mark">(受保护成员函数)</span></td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div">
|
|
<div><a href="cpp-memory-enable_shared_from_this-operator=.html"><span class="t-lines"><span>operator=</span></span></a></div>
|
|
</div>
|
|
</td>
|
|
<td>返回到 <span class="t-c"><span class="mw-geshi cpp source-cpp">this</span></span> 的引用<br />
|
|
<span class="t-mark">(受保护成员函数)</span></td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div">
|
|
<div><a href="cpp-memory-enable_shared_from_this-shared_from_this.html"><span class="t-lines"><span>shared_from_this</span></span></a></div>
|
|
</div>
|
|
</td>
|
|
<td>返回共享 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">*</span>this</span></span> 所有权的 <span class="t-c"><span class="mw-geshi cpp source-cpp">shared_ptr</span></span><br />
|
|
<span class="t-mark">(公开成员函数)</span></td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div">
|
|
<div><a href="cpp-memory-enable_shared_from_this-weak_from_this.html"><span class="t-lines"><span>weak_from_this</span></span></a></div>
|
|
<div><span class="t-lines"><span><span class="t-mark-rev t-since-cxx17">(C++17)</span></span></span></div>
|
|
</div>
|
|
</td>
|
|
<td>返回共享 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">*</span>this</span></span> 所有权的 <span class="t-c"><span class="mw-geshi cpp source-cpp">weak_ptr</span></span><br />
|
|
<span class="t-mark">(公开成员函数)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E6.88.90.E5.91.98.E5.AF.B9.E8.B1.A1">成员对象</span></h3>
|
|
<table class="t-dsc-begin">
|
|
<tr class="t-dsc-hitem">
|
|
<td>成员名</td>
|
|
<td>定义</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><code>weak_this</code> <span class="t-mark">(私有成员对象)</span><span class="t-mark-rev t-since-cxx17">(C++17)</span></td>
|
|
<td>追踪 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">*</span>this</span></span> 的首个共享占有者的控制块的 <span class="t-lc"><a href="cpp-memory-weak_ptr.html">std::weak_ptr</a></span> 对象。仅为说明。</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E6.84.8F">注意</span></h3>
|
|
<p><code>enable_shared_from_this</code> 的常见实现为:其内部保存着一个对 <span class="t-c"><span class="mw-geshi cpp source-cpp">this</span></span> 的弱引用(例如 <span class="t-lc"><a href="cpp-memory-weak_ptr.html">std::weak_ptr</a></span> )。 <span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> 的构造函数检测<span class="t-rev-inl t-since-cxx17"><span>无歧义且可访问的</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span> <code>enable_shared_from_this</code> 基类,并且<span class="t-rev-inl t-since-cxx17"><span>若内部存储的弱引用未为生存的 <span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> 占有,则</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>赋值新建的 <span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> 为内部存储的弱引用。为已为另一 <span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> 所管理的对象构造一个 <span class="t-lc"><a href="cpp-memory-shared_ptr.html">std::shared_ptr</a></span> ,将不会考虑内部存储的弱引用,从而将导致未定义行为。</p>
|
|
<p>只允许在先前已被<span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a></span></span> 管理的对象上调用 <code>shared_from_this</code> 。否则调用<span class="t-rev-inl t-until-cxx17"><span>行为未定义</span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span><span class="t-rev-inl t-since-cxx17"><span>抛出 <span class="t-lc"><a href="cpp-memory-bad_weak_ptr.html">std::bad_weak_ptr</a></span> 异常(通过 shared_ptr 从默认构造的 <code>weak_this</code> 的构造函数)</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。</p>
|
|
<p><code>enable_shared_from_this</code> 提供安全的替用方案,以替代 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="br0">(</span>this<span class="br0">)</span></span></span> 这样的表达式(这种不安全的表达式可能会导致 <span class="t-c"><span class="mw-geshi cpp source-cpp">this</span></span> 被多个互不知晓的所有者析构,见下方示例)。</p>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <memory></span>
|
|
<span class="co2">#include <iostream></span>
|
|
|
|
<span class="kw1">struct</span> Good<span class="sy4">:</span> std<span class="sy4">::</span><span class="me2">enable_shared_from_this</span><span class="sy1"><</span>Good<span class="sy1">></span> <span class="co1">// 注意:继承</span>
|
|
<span class="br0">{</span>
|
|
<a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>Good<span class="sy1">></span> getptr<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> shared_from_this<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> Bad
|
|
<span class="br0">{</span>
|
|
<span class="co1">// 错误写法:用不安全的表达式试图获得 this 的 shared_ptr 对象</span>
|
|
<a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>Bad<span class="sy1">></span> getptr<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> <a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>Bad<span class="sy1">></span><span class="br0">(</span>this<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
~Bad<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <a href="cpp-io-cout.html"><span class="kw1757">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"Bad::~Bad() called<span class="es1">\n</span>"</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="co1">// 正确的示例:两个 shared_ptr 对象将会共享同一对象</span>
|
|
<a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>Good<span class="sy1">></span> gp1 <span class="sy1">=</span> <a href="cpp-memory-shared_ptr-make_shared.html"><span class="kw736">std::<span class="me2">make_shared</span></span></a><span class="sy1"><</span>Good<span class="sy1">></span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>Good<span class="sy1">></span> gp2 <span class="sy1">=</span> gp1<span class="sy2">-</span><span class="sy1">></span>getptr<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1757">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"gp2.use_count() = "</span> <span class="sy1"><<</span> gp2.<span class="me1">use_count</span><span class="br0">(</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 错误的使用示例:调用 shared_from_this 但其没有被 std::shared_ptr 占有</span>
|
|
<span class="kw1">try</span> <span class="br0">{</span>
|
|
Good not_so_good<span class="sy4">;</span>
|
|
<a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>Good<span class="sy1">></span> gp1 <span class="sy1">=</span> not_so_good.<span class="me1">getptr</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span> <span class="kw1">catch</span><span class="br0">(</span><a href="cpp-memory-bad_weak_ptr.html"><span class="kw744">std::<span class="me2">bad_weak_ptr</span></span></a><span class="sy3">&</span> e<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="co1">// C++17 前为未定义行为; C++17 起抛出 std::bad_weak_ptr 异常</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1757">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> e.<span class="me1">what</span><span class="br0">(</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="co1">// 错误的示例,每个 shared_ptr 都认为自己是对象仅有的所有者</span>
|
|
<a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>Bad<span class="sy1">></span> bp1 <span class="sy1">=</span> <a href="cpp-memory-shared_ptr-make_shared.html"><span class="kw736">std::<span class="me2">make_shared</span></span></a><span class="sy1"><</span>Bad<span class="sy1">></span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="cpp-memory-shared_ptr.html"><span class="kw734">std::<span class="me2">shared_ptr</span></span></a><span class="sy1"><</span>Bad<span class="sy1">></span> bp2 <span class="sy1">=</span> bp1<span class="sy2">-</span><span class="sy1">></span>getptr<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1757">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"bp2.use_count() = "</span> <span class="sy1"><<</span> bp2.<span class="me1">use_count</span><span class="br0">(</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="br0">}</span> <span class="co1">// UB : Bad 对象将会被删除两次</span></pre></div>
|
|
</div>
|
|
<p>可能的输出:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="text source-text">
|
|
<pre class="de1">gp2.use_count() = 2
|
|
bad_weak_ptr
|
|
bp2.use_count() = 1
|
|
Bad::~Bad() called
|
|
Bad::~Bad() called
|
|
*** glibc detected *** ./test: double free or corruption</pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<table class="t-dsc-begin">
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div">
|
|
<div><a href="cpp-memory-shared_ptr.html"><span class="t-lines"><span>shared_ptr</span></span></a></div>
|
|
<div><span class="t-lines"><span><span class="t-mark-rev t-since-cxx11">(C++11)</span></span></span></div>
|
|
</div>
|
|
</td>
|
|
<td>拥有共享对象所有权语义的智能指针<br />
|
|
<span class="t-mark">(类模板)</span></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|