Topic: scoped_resource proposal...
Author: Andrew Sandoval <sandoval@netwaysglobal.com>
Date: Wed, 24 Apr 2013 06:08:30 -0700 (PDT)
Raw View
------=_Part_130_30204036.1366808910090
Content-Type: multipart/alternative;
boundary="----=_Part_131_27799910.1366808910090"
------=_Part_131_27799910.1366808910090
Content-Type: text/plain; charset=ISO-8859-1
The last time I sent this out to the group it was overshadowed by the
meetings in Bristol. I've also sent this to lwgchair requesting a document
number but have not yet received a number. I don't know if this is because
I've not properly formatted the specification section, or if there is just
more work than time for lwgchair, but either way I would appreciate
feedback. And again, a request that we focus on what will really help to
make the document worthy of the committee's time -- and not bicker over
whether or not the concept (which we have discussed in detail in another
thread) is worthy. As anyone who has written such a document knows, this
takes an immense amount of time -- something I have in short supply. My
hope is that any inadequacies in the document can be easily remedied.
The latest version of the document is always at
http://www.andrewlsandoval.com/scope_exit/, and the reference
implementation at
http;//www.andrewlsandoval.com/scope_exit/scoped_resource.h.
Thanks Much,
Andrew Sandoval
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_131_27799910.1366808910090
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
The last time I sent this out to the group it was overshadowed by the meeti=
ngs in Bristol. I've also sent this to lwgchair requesting a document=
number but have not yet received a number. I don't know if this is b=
ecause I've not properly formatted the specification section, or if there i=
s just more work than time for lwgchair, but either way I would appreciate =
feedback. And again, a request that we focus on what will really help=
to make the document worthy of the committee's time -- and not bicker over=
whether or not the concept (which we have discussed in detail in another t=
hread) is worthy. As anyone who has written such a document knows, th=
is takes an immense amount of time -- something I have in short supply.&nbs=
p; My hope is that any inadequacies in the document can be easily remedied.=
<br><br>The latest version of the document is always at http://www.andrewls=
andoval.com/scope_exit/, and the reference implementation at http;//www.and=
rewlsandoval.com/scope_exit/scoped_resource.h.<br><br>Thanks Much,<br>Andre=
w Sandoval<br>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_131_27799910.1366808910090--
------=_Part_130_30204036.1366808910090
Content-Type: text/html; charset=windows-1252; name=proposal.html
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename=proposal.html
X-Attachment-Id: 490eb0b6-f4bb-4356-843c-5de7ade12b95
Content-ID: <490eb0b6-f4bb-4356-843c-5de7ade12b95>
<HTML>
<HEAD>
<META NAME=3D"GENERATOR" Content=3D"Microsoft Visual Studio 8.0">
<TITLE>A Proposal to Add additional RAII Wrappers to the Standard Library</=
TITLE>
<style type=3D"text/css">
.style1
{
color: #000099;
}
.style2
{
color: #800000;
}
.style4
{
color: #0000A0;
}
.style5
{
color: #400080;
}
.style6
{
color: #004000;
}
.style7
{
color: #004000;
font-style: italic;
}
.style8
{
color: #FF0000;
}
.style9
{
color: #004000;
font-weight: bold;
}
.style10
{
color: #000000;
}
</style>
</HEAD>
<BODY>
<p><code>
Document Number: Dnnnn=3D12-nnnn<br />
Date: 2012-11-10<br />
Project: Programming Language C++, Library Working Group<br /=
>
Reply-to: Andrew L. Sandoval <sandoval at netwaysglobal dot com&=
gt;<br />
</code>
</p>
<center> <h1>A Proposal to Add additional RAII Wrappers to the Standard Lib=
rary</h1> </center>
<h2>I. Table of Contents</h2>
<ul>
<li>Introduction</li>
<li>Motivation and Scope</li>
<li>Impact on Standard</li>
<li>Design Decisions</li>
<li>Technical Specifications</li>
<li>Acknowledgments</li>
<li>References</li>
</ul>
<h2>II. Introduction</h2>
This proposal seeks to add generic RAII wrappers to the standard library. =
These wrappers will be used to manage the lifetime of various types of reso=
urces and to guarantee the execution of code blocks on scope exit. It buil=
ds on the concept of smart pointers like <code>unique_ptr</code>, but is de=
signed for use with any type of resource=20
that requires clean-up prior to scope exit, as well as any block of cod=
e (via=20
lambda or function invocation) that needs to executed prior to scope ex=
it.
<h2>III. Motivation and Scope</h2>
<p>Quality C++ code requires the use of RAII to manage all types of resourc=
es in=20
order to prevent leakage as well as to limit resource lifetime. R=
esource leakage can occur from the obvious, though often overlooked, failur=
e to clean-up a resource at its intended end-of-life, as well as the less o=
bvious=20
and arguably more common failure to ensure proper handling of resources=
during exception unwinding.</p>
<p>Smart pointers such as <code>unique_ptr</code> and <code>shared_ptr</cod=
e> provide an excellent means of managing the lifetime of pointer types. M=
any other RAII classes have been written to manage the lifetime and limit t=
he scope of locks, such as Boost's <code>boost::lock_guard</code>. All of =
these and the many other types of RAII objects help to=20
substantially improve C++ code quality.
This proposal seeks to add a set of <i>generic</i>, light-weight RAII wra=
ppers intended to manage the scope and lifetime of any other type of resour=
ce. =20
It also proposes an RAII wrapper intended to wrap a function, lambda, o=
r functor=20
which needs to execute prior to scope exit.</p>
<p>There are many types of resources that <i>may</i> not justify encapsulat=
ion in a broader object -- when a simple RAII wrapper around the resource w=
ill suffice or will provide a more obvious implementation.=20
This is especially true when object re-use is not expected. In addition=
, RAII=20
wrappers will simplify the design of objects that <em>do</em> encapsula=
te resources,=20
allowing the generation of, or the declaration of the resource, to also=
declare its method of clean-up. =20
This results in moving resource clean-up outside of an explicit destruc=
tor,=20
which also assures proper order of destruction when initialization orde=
r is=20
correct. This is common practice with pointers managed by <code>u=
nique_ptr</code> and <code>shared_ptr</code>, and even with buffers allocat=
ed and managed by <code>vector</code>.</p>
<p>This proposal requests the addition of the following RAII wrapper types:
<ul>
<li><code><b>scoped_function</b></code></li>
<ul>
<li>Executes a function, functor, or lambda on scope exit.</li>
<li>Is generated with <code><b>make_scoped_function</b>(<i>func</i>=
);</code></li>
<li><code><b>func</b></code> is a function, functor, or lambda that=
takes no parameters. A lambda however may capture=20
and use any scope variables.</li>
</ul>
<li><code><b>scoped_resource_unchecked</b></code></li>
<ul>
<li>Manages a resource's lifetime by executing a deleter function, =
functor, or lambda on scope exit.</li>
<li>Is generated with <code><b>make_scoped_resource_unchecked</b>(<=
i>resource</i>, <i>deleter-func</i>);</code>, or with the=20
more generic <code><b>make_scoped_resource(<i>resource</i>, <i>dele=
ter-func</i>);</b></code></li>
<li><code><b>deleter-func</b></code> is a function, functor, or lam=
bda that takes a single parameter of the same type as <i>resource</i>.</li>
<li>Is suitable for no-fail resources, or other resources in which =
a validity check by comparison to a no-delete value is not possible.</li>
</ul>
<li><code><b>scoped_resource</b></code></li>
<ul>
<li>Manages a resource's lifetime by executing a deleter function, =
functor, or lambda on scope exit, when the resource value can be validated =
by comparison to a no-delete value.</li>
<li>Is generated with <code><b>make_scoped_resource</b>(<i>resource=
</i>, <i>deleter-func</i>, <i>no-delete-value</i>);</code></li>
<li>When generated with <code><b>make_scoped_resource<true></=
b>(<i>resource</i>, <i>deleter-func</i>, <i>no-delete-value</i>);</code> th=
e <code>scoped_resource</code> constructor will throw <code>failed_resource=
_initialization</code> if the resource is equal to the no-delete value.</li=
>
<li><code><b>deleter-func</b></code> is a function, functor, or lam=
bda that takes a single parameter of the same type as <i>resource</i>.</li>
<li><code><b>no-delete-value</b></code> is a value of type <i>resou=
rce</i> that is used to prevent calling <i>deleter-func</i> when the resour=
ce is not valid, as well as to check if the resource is <code>bool <b>valid=
</b>() const;</code></li>
</ul>
<li><code><b>unique_resource</b></code></li>=20
<ul>
<li>Manages a resource's lifetime by executing a <i>constexpr</i> d=
eleter function on scope exit, when the resource value can be validated by =
comparison to a=20
<em>constexpr</em> no-delete value.</li>
<li>It requires template arguments for:</li>
<ol>
<li>The type of a constexpr deleter function, which function ta=
kes a single parameter of the type of the resource, <i>and from which the r=
esource type is deduced</i></li>
<li>The constexpr deleter function itself</li>
<li>A bool value, which when set to true will cause the constru=
ctor to throw <code>failed_resource_initialization</code> if the value pass=
ed to the constructor matches the no-delete value. =20
When false, a validity check is not performed on object con=
struction, but the=20
deleter function will not be executed in the destructor if =
the validity check=20
fails.</li>
<li>A no-delete value of the deduced type of the resource. =
; The types is<i> deduced from the sole parameter to the deleter-func type.=
</i> The default no-delete value is <code>
<span class=3D"style4">static_cast</span><T>(<span cl=
ass=3D"style4">nullptr</span>)</code>.</li>
</ol>
<li>Because of the static or constexpr non-type template arguments =
for the deleter function and the no-delete value:</li>
<ul>
<li>The generated code is very tight and should be roughly the =
equivalent of adding:<br /> <code>if(resource !=3D nodelete) { deleter-func=
(resource); } </code> at a common exit point for the=20
scope.</li>
<li>There is no generator function template.</li>
<li>The no-delete value of the same type as the resource. It i=
s used to prevent calling the deleter function if the resource is not valid=
, as well as to check if the resource is <code>bool valid() const;</code></=
li>
</ul>
<li>Can be constructed without a resource value by using the defaul=
t constructor. =20
This allows the resource value to be set using <code>operator=
=3D</code> at a later time.</li>
</ul>
<h3>A. Motivation for <code>scoped_function</code></h3>
<code>scoped_function</code> is ideal for tying a block of code -- such as =
a lambda to a particular scope, ensuring that the block is invoked prior to=
scope exit.
Two examples should suffice:
<h4>Example <code>scoped_function</code> for mandatory logging on function =
exit:</h4>
<code><pre>
<span class=3D"style4">bool</span> <span class=3D"style2">SomeFunction</spa=
n>(<span=20
class=3D"style4">const</span> input_t &input, modifier_t &modif=
ier, status_t &status)
{
<span class=3D"style6">// Always log the status on scope-exit whether i=
t changes or not...</span>
<span class=3D"style4">auto</span> &&log_status_on_exit =3D <span class=
=3D"style4">std</span>::<span=20
class=3D"style2">make_scoped_function</span>([&status, &modifie=
r]() -><span=20
class=3D"style4">void</span>
{
LogStatus(status, "SomeFunction", modifier);
});
<span class=3D"style4">if</span>(!<span class=3D"style2">AlterationOne<=
/span>(input, modifier, status))
{
<span class=3D"style4">return false</span>;
}
.
.
.
<span class=3D"style4">return</span> <span class=3D"style2">AlterationF=
our</span>(modifier, status);
}
</pre></code>
<h4>Example <code>scoped_function</code> for loop advancement:</h4>
<code><pre>
LegacyDisassembler dis(pInstructionPointer, length);
<span class=3D"style4">while</span>(dis.<span class=3D"style2">RemainingByt=
es</span>())
{
<span class=3D"style6">// Ensure that no matter where else the loop con=
tinues, dis gets advanced...</span>
<span class=3D"style4">auto</span> &&advance =3D <span class=3D"style4"=
>std</span>::<span=20
class=3D"style2">make_scoped_function</span>([&dis]() -><spa=
n=20
class=3D"style4">void</span>
{
dis.<span class=3D"style2">Advance</span>(dis.<span class=3D"style2=
">InstructionLength</span>());
});
<span class=3D"style4">if</span>(dis.<span class=3D"style2">BadInstruct=
ion</span>())
{
std::cerr << "<span class=3D"style8">Error on </span>" << dis << st=
d::endl;
<span class=3D"style4">continue</span>; <span class=3D"style6">//=
Skip the bad byte(s)</span>
}
<span class=3D"style6">// Handle special cases</span>
.
.
.
<span class=3D"style6">// Print the Instruction...</span>
std::cerr << dis.Address << "<span class=3D"style8">: </spa=
n>" << dis << std::endl;
}
</pre></code>
<h3>B. Motivation for <code>scoped_resource_unchecked</code></h3>
<code>scoped_resource_unchecked</code> is ideal for managing a resource tha=
t either can't fail to be initialized, or whose deleter function <i>handles=
</i> exceptional cases (such as an invalid, uninitialized or previously del=
eted resource). =20
It provides no validity checking, and unless <code>release()</code>=
'd the deleter-function=20
will be invoked with the resource on scope exit.
<h4><code>scoped_resource_unchecked</code> example:</h4>
<code>
<pre>
CRITICAL_SECTION cs;
<span class=3D"style2">InitializeCriticalSection</span>(&cs);
<span class=3D"style6">// InitializeCriticalSection() can't fail and return=
s void, but we need the delete to occur prior to scope exit...
// Otherwise it remains on the process's linked-list of active CRITICAL=
_SECTION's.</span>
<span class=3D"style4">auto</span> &&pCS =3D <span class=3D"style4">std</sp=
an>::<span=20
class=3D"style2">make_scoped_resource_unchecked</span>(&cs, <sp=
an=20
class=3D"style2">DeleteCriticalSection</span>); <span class=
=3D"style6">// DeleteCriticalSection can't fail and return void</span>
</pre>
</code>
<h3>C. Motivation for <code>scoped_resource</code></h3>
<code>scoped_resource</code> is designed to handle most resources. It keep=
s the user congnizant of how the resource will be destroyed when it exits s=
cope, and of the condition that must be met.
Though it produces larger object code than <code>unique_resource</code>, =
it benefits from having a generator function template that deduces the temp=
late arguments.
<h4>Example using <code>scoped_resource</code> for with a C API:</h4>
<code>
<pre>
<span class=3D"style6">// Open a file, ensure it is closed when we leave sc=
ope, if the file descriptor is valid...</span>
<span class=3D"style4">auto</span>&& iFileDesc =3D <span class=3D"style4">s=
td</span>::<span=20
class=3D"style2">make_scoped_resource</span>(<span class=3D"sty=
le2">_open</span>(pszPath, <span=20
class=3D"style5">O_WRONLY</span>), <span class=3D"style2">_clos=
e</span>, -1);<span=20
class=3D"style6">=09// if _open returns -1, don't call _close..=
..</span>
<span class=3D"style4">if</span>(iFileDesc.<span class=3D"style2">valid</sp=
an>())
{
<span class=3D"style2">_write</span>(iFileDesc, &data, <span class=3D"s=
tyle4">sizeof</span>(data));
}
</pre>
</code>
This could also be done using exception handling=20
(where exception handling is allowed and expected)...
<code>
<pre>
<span class=3D"style4">try</span>
{
<span class=3D"style6"> // Open a file, ensure it is closed when we leav=
e scope, if the file descriptor is valid...</span>
<span class=3D"style4"> auto</span>&& iFileDesc =3D <span class=3D"style=
4">std</span>::<span=20
class=3D"style2">make_scoped_resource</span>(<span class=3D"sty=
le2">_open</span>(pszPath, <span=20
class=3D"style5">O_WRONLY</span>), <span class=3D"style2">_clos=
e</span>, -1);<span=20
class=3D"style6">=09// if _open returns -1, throw...</span>
<span class=3D"style2">_write</span>(iFileDesc, &data, <span class=3D"s=
tyle4">sizeof</span>(data));
}
<span class=3D"style4">catch</span> (<span class=3D"style4">const std::fail=
ed_resource_initialization</span> &e)
{
std::cout << "<span class=3D"style8">Exception: </span>" <<=
e.<span=20
class=3D"style2">what</span>() << std::endl;
<span class=3D"style4">return false</span>;
}
<span class=3D"style4">return true</span>;
</pre>
</code>
<h4>Example using <code>scoped_resource</code> for with a Windows API:</h4>
<pre>
<code>
<span class=3D"style6">// Create or open an event handle, wait on it, but a=
fter being signalled close the handle...</span>
<span class=3D"style6">// Don't CloseHandle() if we don't have permissions =
to open it, etc.</span>
<span class=3D"style6">// Another exception-free example, that with differe=
nt calls could be used in kernel-mode</span>
<span class=3D"style4">const HANDLE</span> INVALID_EVENT_HANDLE =3D <span c=
lass=3D"style4">static_cast</span><<span=20
class=3D"style4">HANDLE</span>>(<span class=3D"style4">nullp=
tr</span>);
<span class=3D"style4">auto</span> hEvent =3D <span class=3D"style4">std</s=
pan>::<span=20
class=3D"style2">make_scoped_resource</span>(<span class=3D"sty=
le2">CreateEvent</span>(<span=20
class=3D"style4">nullptr</span>, TRUE, FALSE, <span class=3D"st=
yle4">nullptr</span>), <span=20
class=3D"style2">CloseHandle</span>, INVALID_EVENT_HANDLE);
<span class=3D"style4">if</span>(!hEvent.<span class=3D"style4">valid</span=
>())
{
<span class=3D"style4">return false</span>; <span class=3D"style6">//=
CloseHandle will not be called</span>
}
DWORD dwWait =3D <span class=3D"style2">WaitForSingleObject</span>(hEvent, =
1000);
..
..
..
<span class=3D"style6">// CloseHandle() will be called as soon as hEvent le=
aves scope</span>
</pre>
</code>
NOTE: Microsoft defines <code>INVALID_HANDLE_VALUE</code> as <code>-1</code=
> for the <code>CreateFile</code> API, but returns <code>NULL</code> for mo=
st other APIs. Compliant compilers can handle the case where <code>INVALID=
_HANDLE_VALUE</code> is passed to <code>scoped_ptr</code> as a no-delete va=
lue. =20
Unfortunately this is not true of some c++11 compliant compilers (s=
uch as g++) when <code>INVALID_HANDLE_VALUE</code> is passed as a non-type =
template parameter:
<code><pre>
<span class=3D"style4">auto</span>&& hFile =3D <span class=3D"style4">std</=
span>::<span=20
class=3D"style2">make_scoped_resource</span>(<span class=3D"sty=
le2">CreateFileW</span>(pwzPath, FILE_GENERIC_WRITE, FILE_SHARE_WRITE, <spa=
n=20
class=3D"style4">nullptr</span>, CREATE_ALWAYS, FILE_ATTRIBUTE_=
NORMAL, <span=20
class=3D"style4">nullptr</span>),
<span class=3D"style2">CloseHandle</span>, <span class=3D"style5">INVAL=
ID_HANDLE_VALUE</span>);<span=20
class=3D"style6"> // Compiles fine</span>
</pre>
<pre>
<span class=3D"style4">std</span>::<span class=3D"style4">unique_resource</=
span><<span=20
class=3D"style5">UNIQUE_DELETER</span>(<span class=3D"style2">C=
loseHandle</span>),<span=20
class=3D"style5"> INVALID_HANDLE_VALUE</span>> <span class=
=3D"style6">// Compiler error on gcc-4.7, compiles on Visual Studio 2010</s=
pan>
hFile(<span class=3D"style2">CreateFileW</span>(pwzPath, FILE_GENERIC_W=
RITE, FILE_SHARE_WRITE, <span=20
class=3D"style4">nullptr</span>, CREATE_ALWAYS, FILE_ATTRIBUTE_=
NORMAL, <span=20
class=3D"style4">nullptr</span>));
</pre>
</pre></code>
<h3>D. Motivation for <code>unique_resource</code></h3>
<p>The primary motivation for using <code>unique_resource</code> over <code=
>scoped_resource</code>=20
is the size of the generated object code. It's use is restricted =
to resources that have a constexpr deleter function which takes a single ar=
gument of the same type as the resource.
Also, the deleter function and the no-delete value must be constant express=
ions.<br /></p>
<p>There is no generator like <code><nobr>make_scoped_resource()</nobr></co=
de> for <code>unique_resource</code>. It's construction requires=20
4 template parameters, but unlike <code><nobr>make_scoped_resource()</n=
obr></code>, the static=20
(constexpr) no-delete value has a default value of <code><span class=3D=
"style4">static_cast</span><T>(<span=20
class=3D"style4">nullptr</span>)</code>, where <code>T</code> is th=
e type of the first argument passed to the deleter function.<br /></p>
<p>In the reference implementation <code>unique_resource</code> uses a pare=
nt implementation class called <code>unique_resource_impl</code>. This all=
ows the type of the resource to be deduced using template metaprogramming. =
<code>unique_resource_impl</code> requires=20
5 template parameters. The <code>TFuncInfo1</code> template resolves t=
he parameter type of the deleter function for <code>unique_resource</code> =
which inherits from <code>unique_resource_impl</code>.<br /></p>
<p>To simplify use of <code>unique_resource</code>, a convenience macro is =
used in the examples below, and in the reference implementation. It is def=
ined as:</p>
<code><pre>#<span class=3D"style4">define</span> <span class=3D"style5">UNI=
QUE_DELETER</span>(deleter_fn) decltype(&deleter_fn), deleter_fn, <span=20
class=3D"style4">false</span>
#<span class=3D"style4">define</span> <span class=3D"style5">UNIQUE_DELETER=
_THROW</span>(deleter_fn) decltype(&deleter_fn), deleter_fn, <span=20
class=3D"style4">true</span></pre></code>
<p>Another consideration when using <code>unique_resource</code> over <code=
>make_scoped_resource()</code> is the benefit it provides for member variab=
le resources. For example, both of the following classes will accomplish t=
he same end-goal, of calling <code>CloseHandle</code>
on <code>m_hEvent</code> when an instance of the class is destroyed, but t=
he <code>unique_resource</code> example is slightly easier to read, especia=
lly with the help of <code>UNIQUE_DELETER</code>.
<code>
<pre>
<span class=3D"style4">class</span> TestClassMember
{
<span class=3D"style4">private</span>:
<span class=3D"style6">// auto &&m_hEvent; // error C3531: 'm_hEvent': =
a symbol whose type contains 'auto' must have an initializer</span>
<span class=3D"style4">std</span>::<span class=3D"style2">scoped_resour=
ce</span><<span=20
class=3D"style4">decltype</span>(&<span class=3D"style2">CloseH=
andle</span>), HANDLE> m_hEvent;=09<span=20
class=3D"style6">// </span><span class=3D"style9">ok, but a bit=
bulky... And a macro can't deduce the resource type...</span>
<span class=3D"style4">public</span>:
<span class=3D"style6">// TestClassMember() : m_hEvent(std::make_scoped=
_resource(CreateEvent(nullptr, TRUE, FALSE, nullptr), [](HANDLE hEvent) { i=
f(hEvent) CloseHandle(hEvent); }))</span>
<span class=3D"style6"> // { // ^^: error C2440: 'initializing' : canno=
t convert from 'std::scoped_resource_unchecked<T,R>' to 'int'</span>
<span class=3D"style6"> // }</span>
TestClassMember() : m_hEvent(<span class=3D"style4">std</span>::<span c=
lass=3D"style2">make_scoped_resource</span>(<span=20
class=3D"style2">CreateEvent</span>(<span class=3D"style4">null=
ptr</span>, TRUE, FALSE, <span=20
class=3D"style4">nullptr</span>), <span class=3D"style2">CloseH=
andle</span>, <span=20
class=3D"style4">static_cast</span><HANDLE>(<span class=3D"styl=
e4">nullptr</span>)))
{
<span class=3D"style6">// ^^ </span><span class=3D"style9">This how=
ever works, but it isn't quite as easy to follow as the example in TestClas=
sMember2</span>
}
<span class=3D"style4">void</span> Wait()
{
DWORD dwX =3D <span class=3D"style2">WaitForSingleObject</span>(m_h=
Event, <span=20
class=3D"style5">INFINITE</span>);
<span class=3D"style6">// Other stuff here...</span>
}
<span class=3D"style4">void</span> Set()
{
<span class=3D"style2">SetEvent</span>(m_hEvent);
}
<span class=3D"style6">// Other stuff here...</span>
};
<span class=3D"style4">class</span> TestClassMember2
{
<span class=3D"style4">private</span>:
<span class=3D"style4">std</span>::<span class=3D"style4">unique_resour=
ce</span><<span=20
class=3D"style5">UNIQUE_DELETER</span>(<span class=3D"style2">C=
loseHandle</span>)> m_hEvent;
<span class=3D"style6"> // </span><span class=3D"style9">^^ This is easy=
to understand, ^^ draws attention to the deleter function</span>
<span class=3D"style4">public</span>:
TestClassMember2() : m_hEvent(<span class=3D"style2">CreateEvent</span>=
(<span=20
class=3D"style4">nullptr</span>, TRUE, FALSE, <span class=3D"st=
yle4">nullptr</span>)) <span=20
class=3D"style6">// </span><span class=3D"style9">Initializatio=
n is natural, similar to the raw resource type</span>
{
}
<span class=3D"style4">void</span> Wait()
{
DWORD dwX =3D <span class=3D"style2">WaitForSingleObject</span>(m_h=
Event, <span=20
class=3D"style5">INFINITE</span>);
<span class=3D"style6">// Other stuff here...</span>
}
<span class=3D"style4">void</span> Set()
{
<span class=3D"style2">SetEvent</span>(m_hEvent);
}
<span class=3D"style6">// Other stuff here...</span>
};
</code>
</pre>
</p>
<h4>Example of <code>unique_resource</code> compared to a <code>scoped_reso=
urce</code> generated with <code><nobr>make_scoped_resource()</nobr></code>=
</h4>
The following two (obviously useless) functions were compiled with Visual S=
tudio 2010 for 32-bit Windows. Notice that the code generated by <code><no=
br>test_unique_resource()</nobr></code> is only 32 bytes, compared to the 5=
7 byte <code><nobr>test_scoped_resource()</nobr></code>, which does the sam=
e thing.
<code>
<pre>
<span class=3D"style1">void</span> <span class=3D"style2">test_unique_resou=
rce</span>(...) <span=20
class=3D"style6">//... added to prevent inlining</span>
{
<span class=3D"style6">// Create an event which will be closed on scope=
-exit, if NOT NULL. It can be passed to SetEvent/WFSO as hEvent</span>
<span class=3D"style4"> std</span><span class=3D"style10">::</span><span=
class=3D"style4">unique_resource</span><<span class=3D"style5">UNIQUE_D=
ELETER</span>(<span=20
class=3D"style2">CloseHandle</span>)> hEvent(<span=20
class=3D"style2">CreateEvent</span>(<span class=3D"style4">null=
ptr</span>, TRUE, FALSE, <span=20
class=3D"style4">nullptr</span>));
}
<span class=3D"style6">// Object Code: (32 bytes, no prologue, no epilogue,=
1 byte for ret)</span>
<span class=3D"style6">// scope_exit!test_unique_resource [scope_exit\scope=
_exit.cpp @ 243]:</span>
<span class=3D"style6">// 243 003d1310 6a00 push 0</span>
<span class=3D"style6">// 245 003d1312 6a00 push 0</span>
<span class=3D"style6">// 245 003d1314 6a01 push 1</span>
<span class=3D"style6">// 245 003d1316 6a00 push 0</span>
<span class=3D"style6">// 245 003d1318 ff1510303d00 call dword ptr =
[scope_exit!_imp__CreateEventW (003d3010)]</span>
<span class=3D"style6">// 246 003d131e 85c0 test eax,eax</s=
pan>
<span class=3D"style6">// 246 003d1320 7407 je scope_exit=
!test_unique_resource+0x19 (003d1329)</span>
<span class=3D"style6">// 246 003d1322 50 push eax</span>
<span class=3D"style6">// 246 003d1323 ff1514303d00 call dword ptr =
[scope_exit!_imp__CloseHandle (003d3014)]</span>
<span class=3D"style6">// 246 003d1329 c3 ret</span>
<span class=3D"style6">////////////////////////////////////////////////////=
///////////////////////////</span>
<span class=3D"style6">////////////////////////////////////////////////////=
///////////////////////////</span>
<span class=3D"style4">const HANDLE</span> INVALID_EVENT_HANDLE =3D <span c=
lass=3D"style4">static_cast</span><<span=20
class=3D"style4">HANDLE</span>>(<span class=3D"style4">nullp=
tr</span>);
<span class=3D"style4">void</span> <span class=3D"style2">test_scoped_resou=
rce</span>(...) <span=20
class=3D"style6"> //... added to prevent inlining</span>
{
<span class=3D"style6">// Create an event which will be closed on scope=
-exit, if NOT NULL. It can be passed to SetEvent/WFSO as hEvent</span>
<span class=3D"style4">auto</span> hEvent =3D <span class=3D"style4">st=
d</span>::<span=20
class=3D"style2">make_scoped_resource</span>(<span class=3D"sty=
le2">CreateEvent</span>(<span=20
class=3D"style4">nullptr</span>, TRUE, FALSE, <span class=3D"st=
yle4">nullptr</span>), <span=20
class=3D"style2">CloseHandle</span>, INVALID_EVENT_HANDLE);
}
<span class=3D"style6">// Object Code: (57 bytes, 3 prologue bytes and 3 ep=
ilogue bytes, </span><span=20
class=3D"style7">to allow for scoped_resource (12 bytes, aligne=
d) on the stack</span><span=20
class=3D"style6">, + 1 for ret)</span>
<span class=3D"style6">// scope_exit!test_scoped_resource [scope_exit.cpp @=
250]:</span>
<span class=3D"style6">// 250 003d1330 55 push ebp</span>
<span class=3D"style6">// 250 003d1331 8bec mov ebp,esp</s=
pan>
<span class=3D"style6">// 250 003d1333 83ec0c sub esp,0Ch</s=
pan>
<span class=3D"style6">// 252 003d1336 6a00 push 0</span>
<span class=3D"style6">// 252 003d1338 6a00 push 0</span>
<span class=3D"style6">// 252 003d133a 6a00 push 0</span>
<span class=3D"style6">// 252 003d133c 6a01 push 1</span>
<span class=3D"style6">// 252 003d133e 6a00 push 0</span>
<span class=3D"style6">// 252 003d1340 ff1510303d00 call dword ptr =
[scope_exit!_imp__CreateEventW (003d3010)]</span>
<span class=3D"style6">// 252 003d1346 8b0d14303d00 mov ecx,dword =
ptr [scope_exit!_imp__CloseHandle (003d3014)]</span>
<span class=3D"style6">// 252 003d134c 8bd0 mov edx,eax</s=
pan>
<span class=3D"style6">// 252 003d134e 8d45f4 lea eax,[ebp-0=
Ch]</span>
<span class=3D"style6">// 252 003d1351 e83a060000 call scope_exit=
!std::make_scoped_resource<int (__stdcall*)(void *),void *> (003d1990=
)</span>
<span class=3D"style6">// 253 003d1356 8b45f8 mov eax,dword =
ptr [ebp-8]</span>
<span class=3D"style6">// 253 003d1359 83c404 add esp,4</spa=
n>
<span class=3D"style6">// 253 003d135c 3b45fc cmp eax,dword =
ptr [ebp-4]</span>
<span class=3D"style6">// 253 003d135f 7404 je scope_exit=
!test_scoped_resource+0x35 (003d1365)</span>
<span class=3D"style6">// 253 003d1361 50 push eax</span>
<span class=3D"style6">// 253 003d1362 ff55f4 call dword ptr =
[ebp-0Ch]</span>
<span class=3D"style6">// 253 003d1365 8be5 mov esp,ebp</s=
pan>
<span class=3D"style6">// 253 003d1367 5d pop ebp</span>
<span class=3D"style6">// 253 003d1368 c3 ret</span>
</pre></code>
<h3>Reference Implementation</h3>
<ul>
<li><a href=3D"http://www.andrewlsandoval.com/scope_exit/scoped_resource.h"=
>http://www.andrewlsandoval.com/scope_exit/scoped_resource.h</a> : <code><b=
><scoped_resource></b></code> header file</li>
<li><a href=3D"http://www.andrewlsandoval.com/scope_exit/scope_exit.cpp">ht=
tp://www.andrewlsandoval.com/scope_exit/scope_exit.cpp</a> : <code><b>scope=
_exit.cpp</b></code> file with tests</li>
<ul><li>Compiles on Windows x86 and x64, using Visual Studio 2010+ and MinG=
W g++ 4.7</li>
<li>Should compile on other platforms if Windows specific APIs are not used=
</li></li></ul>=20
</ul>
<h3>Scope</h3>
As demonstrated above, the scope of this proposal is intended to provide th=
e 4 new classes and 3 new function templates (as a generator for those=20
the first three classes), to allow wrapping any type of resource or=
code block in an object that ensures execution or clean-up=20
of a resource on scope exit. There will be no impact on users that=
opt not to use <code>scoped_resource</code>. Otherwise the impact and sco=
pe should be much the same as the impact and scope of <code>unique_ptr</cod=
e>, only=20
with the intended use focused on non-pointer resources, and pointer=
based=20
resources for which one of these wrappers may be a better fit than =
<code>unique_ptr</code>.
<h3>Final Notes on Motivations and Scope:</h3>
NOTE: Despite similarity in name, this proposal is not related to Boost's S=
cope.Exit. Though the goals are similar Scope.Exit uses macros to achieve =
its goals.
<h2>IV. Impact on Standard</h2>
This proposal is a pure library extension. It proposes adding a new header,=
<code><scope_resource></code>, but it does not require changes to an=
y standard classes or functions. It does not require any changes in the cor=
e language, and it has been implemented in standard C++ conforming to c++11=
.. The proposal does not depend on any other library extensions. The refere=
nce implementation utilizes the standard <code><utility></code>=20
header, for <code>std::move</code>, as well as <code><type_traits>=
;</code> for <code>std::remove_pointer</code>, and <code>std::add_reference=
</code>.
<h2>V. Design Decisions</h2>
<h3>A. General Principles</h3>
<ol>
<li>Simplicity</li>
<blockquote>Using an RAII resource wrapper should be as easy as using a raw=
data=20
type. Generally the cast operator accomplishes this goal. The <co=
de>get()</code> method=20
would be a reasonable alternative to the cast operator if it were to me=
et with insurmountable opposition. =20
Other operators are also provided to simplify usage in a natural manner=
for the wrapped resource.</blockquote>
<blockquote>Simple construction and generation should encourage use of the =
wrappers over raw resource types. This is as true when resources are used w=
ithin functions and methods as it is when the wrappers are used in objects =
designed to encapsulate and provided additional related functionality aroun=
d the resource in a class.</blockquote>
<blockquote>The "generator" function templates <code>make_scoped_function</=
code>, and <code>make_scoped_resource</code> help ensure simplicity.</block=
quote>
<blockquote>Though macros are generally frowned upon, the <code>UNIQUE_DELE=
TER</code> macro used to simplify the passing of template parameters to <co=
de>unique_resource</code>, can also claim to improve simplicity.
Unlike other macros, it does not hide functionality -- instead it draws a=
ttention to the the template arguments that matter most. The end result is=
a very easy to use and understand <code>unique_resource</code>.</blockquot=
e>
<blockquote>Code written with these RAII wrappers becomes simple to maintai=
n. Lifetime of resources and their method of clean-up is evident from the =
time of declaration or generation. The order of operations in clean-up is =
expected and simple. And object lifetime is managed by scope rather than t=
he hopefully correct ordering of clean-up at scope-exit or in traditional d=
estructors.</blockquote>
<li>Transparency</li>
<blockquote>It should be obvious from a glance what each RAII resource wrap=
per does. Constructors and generator function templates should clearly sho=
w the binding of the resource's clean-up to the resource. =20
Similarly a glance at a <code>scoped_function</code> should make it obv=
ious what will happen when the object reaches scope exit.</blockquote>
<li>Resource Conservation and Lifetime Management</li>
<blockquote>Each wrapper is designed to encourage consideration of a resour=
ce's lifetime when it is created. The cost of using these wrappers should =
not out weigh the benefits.</blockquote>
<li>Generated Object Code Size</li>
<blockquote>Code bloat should be avoided, and options should exist to minim=
ize generated object code size. These wrappers should be usable in resourc=
e constrained environments.</blockquote>
<li>Exception Safety</li>
<blockquote>These RAII resource wrappers should be able to be used without =
introducing any new risk of throwing exceptions due to allocation failures,=
etc. They should be usable for example in kernel code where C++ exception=
s often can't be handled.</blockquote>
<blockquote>Both types of RAII wrappers that allow for a vailidity check (<=
code>scoped_resource</code>, and <code>unique_resource</code>) default to a=
<b>nothrow</b> implementation. Each also offer a=20
simple means by which <code>failed_resource_initialization</code> may b=
e thrown on construction when a validity check fails. =20
This provides the broadest opportunity for use, and adaptation to the u=
sers=20
needs.</blockquote>
<li>Use of Lambdas</li>
<blockquote>These RAII resource wrappers should allow for the use of lambda=
s with and without capturing. =20
Because lambda's may be used to capture by reference, these RAII wr=
appers can utilize or update references just prior to scope-exit, etc. =
; Lambda's also provide a means of adding logic to deleter "functions", and=
of returning status from a deleter function.</blockquote>
</ol>
<p>B. Prior implementations</p>
<ol>
<li>RAIIFunction and RAIIWrapper</li>
<blockquote><code>RAIIFunction</code> and <code>RAIIWrapper</code> have bee=
n in shipping commercial products. They were initially posted to std-propo=
sals to begin the discussion leading to this proposal. <code>RAIIWrapper</=
code> is very similar to <code>unique_resource</code>.
<code>RAIIFunction</code> was original designed to inherit from <code>std=
::function<void ()></code>, and was later changed to use the same in =
composition. This class was posted to the Boost Developer mailing list, wh=
ere encouragement and feedback where given on possible inclusion in Boost. =
It was noted however that <code>std::function</code> can throw on an alloc=
ation failure. This was mentioned when posting to the std-proposals list, =
and=20
the current solution -- of using template types (and generator function t=
emplates) instead of <code>std::function<void ()></code> was recommen=
ded by one of the list participants (DeadMG). <code>scoped_function</code>=
, <code>scoped_resource_unchecked</code>, and <code>scoped_resource</code> =
along with their <code>make_scoped_function</code> and <code>make_scoped_re=
source()</code> generators are the result of reworking <code>RAIIFunction</=
code> based on feedback from the group in general.
The result is a much more usable set of classes, where lambda's can be us=
ed to clean-up resources with or without capturing, etc.
</blockquote>
<li>Boost Scope.Exit</li>
<blockquote>
During discussion on the Boost Developer mail list, attention was drawn to =
the Boost Scope.Exit library. This library uses macros to provide the abil=
ity to execute clean-up code on scope exit. For the purposes of this propo=
sal, macros have been avoided, other than the very simple <code>UNIQUE_DELE=
TER</code> macro that is used only for template parameters. Macros often h=
ide details, including from debuggers, that can be crucial to understand an=
d troubleshooting problems. For that reason, and because of the general di=
staste for macros in C++, Boost Scope.Exit was not considered for this prop=
osal. =20
That should not be in anyway interpreted as disrespect to the author of Boo=
st Scope.Exit, as it was designed to work with earlier C++ compilers that l=
ack C++11 support. It should also be noted that the Boost Scope.Exit docum=
entation also includes a suggested alternative for a class compositing <cod=
e>std::function<void (void)></code><sub><b><a href=3D"#reference1">1<=
/a></b></sub>.
</blockquote>
<li>std::unique_ptr</li>
<blockquote>During discussions on the std-proposal list, many examples were=
given, and some suggestions that <code>std::unique_ptr</code> is sufficien=
t and additional RAII classes are not needed. This proposal rejects those =
suggestions. =20
Though <code>std::unique_ptr</code> is vital to the Standard Library it is =
designed to work with pointers, not resources of other types.
Converting resources, whether they are <code>int</code>'s of a file descrip=
tors, or other non-pointer types isn't straightforward -- and requires that=
the deleter be able to dereference the pointer. That would rule out use w=
ith many functions, unless the deleter function was first wrapped in a lamb=
da or another function or functor for that purpose.
Additionally, <code>std::unique_ptr</code> does not provide a cast operat=
or to allow natural use of the wrapped resource in API calls, etc.
</blockquote>
<li>ScopeGuard</li>
<blockquote>
An article<sub><b><a href=3D"#reference2">2</a></b></sub> written by Andrei=
Alexandrescu and Petru Marginean, published by Dr. Dobbs Magazine in Decem=
ber 2000 introduces a class called <code>ScopeGuard</code>, which is very s=
imilar to <code>scope_resource_uc</code> as presented in the reference impl=
ementation associated with this proposal.
</blockquote>
</ol>
<p>C. Risks</p>
<blockquote>
The cast operator provided by each of the classes does pose a minor risk. =
For example, if a confused user where to try to to mix the <code>make_scope=
d_resource()</code> call with construction of a <code>unique_resource</code=
>, the cast operator will allow initialization of <code>unique_resource</co=
de>,=20
but the return of the <code>make_scoped_resource()</code> will result in a =
temporary object, which after transfering the wrapped resource to the <code=
>unique_resource</code> will then be "deleted" by the deleter function pass=
ed to <code>make_scoped_resource</code>. This would lead to the deleter be=
ing invoked more than once, and the resource being used after deletion.
This is a minor risk. The template parameters to <code>unique_resource</=
code> should make it obvious that it does not match up to <code>make_scoped=
_resource()</code>.
</blockquote>
<h2>VI. Technical Specifications</h2>
<h3>Header</h3>
Add an extra row to table 44
<center>
<table border>
<caption>Table 44 — General utilities library summary</caption>
<tr><td>Subclause</td><td>Header(s)</td>
<tr><td>20.14 Scoped resources</td><td><code><scoped_resource></code=
></td>
</tr>
</tr>
</table>
</center>
<h3>20.14 Scoped resources</h3>
<h3>20.14.1 Class template <code>scoped_function</code></h3>
<table>
<tr><td>1</td><td>A <i>scoped function</i> is an object <i>s</i> that manag=
es a function object <i>f</i> such that <i>f</i> will be invoked when <i>s<=
/i> is destroyed (e.g., when leaving block scope (6.7)).</td></tr>
<tr><td>2</td><td>The function object managed by <code>scoped_function<T=
></code> takes no parameters, so that <i>s</i> may invoke <i>f</i> as <c=
ode>f();</code>.</td></tr>
<tr><td>3</td><td><i>f</i> may be a function pointer, functor, callable fun=
ction as returned from <code>std::bind</code>, or a lambda=20
taking no parameters.</td></tr>
</table>
<code>
<pre>
namespace std
{
template<typename T> class scoped_function
{
public:
// 20.14.1.1 constructors
explicit scoped_function(T&& f) noexcept;
explicit scoped_function(const T& f) noexcept;
// 20.14.1.2 destructor
~scoped_function();
// 20.14.1.3 modifiers
scoped_function& release() noexcept();
scoped_function& reset(T&& f);
scoped_function& reset(const T& f);
scoped_function& invoke(bool bRelease =3D true);
void operator()();
// 20.14.1.4 assignment
void operator=3D(T&& f) noexcept;
void operator=3D(const T& f) noexcept;
};
// 20.14.1.5 generator
// Make a scoped_function
// Takes 1 parameter - the function to be run on scope exit...
template<typename T> scoped_function<T> make_scoped_functio=
n(T f) noexcept;
{
return scoped_function<T>(std::move(f));
}
}
</pre>
</code>
<p>
<h4>20.14.1.1 scoped_function constructors</h4>
The <code>scoped_function</code> constructors take one argument, the type o=
f which must be a callable function taking no parameters. It is intended t=
hat <code>std::make_scoped_function( f )</code> be used to generate a <code=
>scoped_function</code>, as in the following examples:
<code><pre>
//
// Using a lambda:
auto logOnScopeExit =3D std::make_scoped_function([&syslog, &someStateVaria=
ble]() ->void
{
syslog << "Exiting with state: " << someStateVariable;
});
//
// Using a function:
// e.g. void SetFinalStatus();
auto setFinalStatus =3D std::make_scoped_function(SetFinalStatus);
//
// Using bind
auto closeFile =3D std::make_scoped_function( std::bind(close, fd) ); /=
/ std::bind may throw
</pre></code>
</p>
<h4>20.14.1.2 scoped_function's destructor</h4>
The <code>scoped_function</code> destructor will invoke the function object=
passed to the constructor, as long as the <code>scoped_function</code> has=
not been "released" via a call to <code>release()</code>, or <code>invoke(=
true)</code>.
<h4>20.14.1.3 scoped_function's modifiers</h4>
<ul>
<li><code>release()</code> instructs <code>scoped_function</code> that the =
function passed to the constructor (or reset / assignment operators) is not=
to be called when the destructor is invoked.</li>
<li><code>reset()</code> accepts a new function, function object, or lambda=
to be called when the <code>scoped_function</code> destructor is invoked. =
The argument is the same as what is accepted by the constructors. Resetin=
g the function also resets the state of a previously "released" <code>scope=
d_function</code></li>
<li><code>invoke(true)</code> performs an early (pre-destructor) invocation=
of the function passed to the constructor, reset method, or assignment ope=
rator. The default true parameter sets the <code>scoped_function</code> to=
the "released" state so that the function will not be invoked again when t=
he destructor is called.</li>
<li><code>invoke(false)</code> performs an early (pre-destructor) invocatio=
n of the function passed to the constructor, reset method, or assignment op=
erator. The false parameter leaves the <code>scoped_function</code> in the=
"unreleased" state so that the function <b>will</b> be invoked again when =
the destructor is called.</li>
<li><code>operator()()</code> performs an early (pre-destructor) invocation=
of the function passed to the constructor, the same as if <code>invoke(tru=
e)</code> had been called.</li>
</ul>
<h4>20.14.1.4 scoped_function's assignment operators</h4>
The assignment operator invokes <code>reset()</code> to replace the functio=
n that will be invoked when the destructor is called. The object is set to=
the "unreleased" state so that even if <code>release()</code>, or <code>in=
voke(true)</code> had been previously called, the new function will be invo=
ked when the destructor is called.
<h4>20.14.1.5 <code>make_scoped_function</code></h4>
<code>make_scoped_function(func)</code> is used to generate a <code>scoped_=
function</code> object.
<h3>20.14.2 Class template <code>scoped_resource_unchecked</code></h3>
<table>
<tr><td>1</td><td>A <i>scoped_resource_unchecked</i> is an object <i>s<=
/i> that manages a generic resource <i>r</i> such that a clean-up function,=
function object, or lambda, <i>f(r)</i> will be invoked when <i>s</i> is d=
estroyed (e.g., when leaving block scope (6.7)).</td></tr>
<tr><td>2</td><td>The function object <i>f</i> managed by <code>scoped_=
resource_unchecked<TDel,=20
TRes></code> takes a single parameter of the type of the resourc=
e <i>r</i> so that <i>s</i> may invoke <i>f(r)</i> as <code>f(r);</code>, w=
hen <i>s</i> leaves the current scope.</td></tr>
<tr><td>3</td><td><i>f</i> may be a function pointer, functor, a callab=
le function as returned from <code>std::bind</code>, or a lambda, taking a =
single argument of the type of the resource.</td</tr>
<tr><td>4</td><td><i>r</i> may be accessed through cast operators as if=
it were of the type of the resource <i>r</i>.</td></tr>
<tr><td>5</td><td>Unlike scoped_resource, <i>r</i> is not compared to a=
"no-delete value" prior to the invocation of <code>f(r)</code>.</td></tr>
<tr><td>6</td><td>A <code>scoped_resource_unchecked</code> may be gener=
ated (is intended to be generated) using <code>make_scoped_resource(r, f)</=
code></td></tr>
</table>
<code>
<pre>
namespace std
{
template<typename TDel, typename TRes> class scoped_resource_unch=
ecked
{
public:
// 20.14.2.1 constructors
explicit scoped_resource_unchecked(TDel&& arg, TRes&& resource) noe=
xcept;
explicit scoped_resource_unchecked(const TDel& arg, const TRes& res=
ource) noexcept;
// 20.14.2.2 destructor
~scoped_resource_unchecked();
// 20.14.2.3 modifiers
TRes release() throw();
scoped_resource_unchecked& reset(TRes&& resource);
scoped_resource_unchecked& reset(const TRes& resource);
scoped_resource_unchecked& invoke(bool bRelease =3D true);
void operator()();
// 20.14.2.4 access
TRes get() const throw();
operator TRes() const throw();
TRes operator->() const;
TRes* operator&();
TDel& get_deleter();
const TDel& get_deleter() const;
};
// 20.14.2.5 Specific Generator
// Make a scoped_resource_unchecked (unchecked)
// Takes 2 arguments: The resource and the deleter
template<typename TDel, typename TRes>
scoped_resource_unchecked<TDel, TRes> make_scoped_resource_unchec=
ked(TRes r, TDel d) throw() // Specific request
{
return scoped_resource_unchecked<TDel, TRes>(std::move(d), st=
d::move(r));
}
// 20.14.2.6 Generic Generator
template<typename TDel, typename TRes>
scoped_resource_unchecked<TDel, TRes> make_scoped_resource(TRes r=
, TDel d) throw() // Generic request
{
return scoped_resource_unchecked<TDel, TRes>(std::move(d), st=
d::move(r));
}
}
</pre>
</code>
<p>
<h4>20.14.2.1 scoped_resource_unchecked constructors</h4>
The <code>scoped_resource_unchecked</code> constructors take two arguments.=
The type of the first must be a callable function taking a single paramete=
r of the type of the second template argument. It is intended that <code>s=
td::make_scoped_resource(resource, deleter)</code> be used to generate a <c=
ode>scoped_resource_unchecked</code>, as in the following examples:
<code><pre>
//
// Most common usage - close "handle" types on scope-exit, using a function=
....
extern PACCESS_TOKEN PsReferencePrimaryToken(IN PEPROCESS pProcess); // =
Assumption: Always returns a valid value that can be passed to ObDerference=
Token
extern void ObDereferenceToken(PACCESS_TOKEN pToken); // =
Deleter: Handles any value (including nullptr) from PsReferencePrimaryToken=
()
// Manual Construction (not intended):
std::scoped_resource_unchecked<decltype(&ObDereferenceToken), PACCESS_TO=
KEN> pToken(PsReferencePrimaryToken(PsGetCurrentProcess(), ObDereference=
Token));
// Construction via Generic Generator (preferred method) (see 20.14.2.6):
auto pToken =3D std::make_scoped_resource(PsReferencePrimaryToken(PsGetCurr=
entProcess(), ObDereferenceToken));
//
// Using a lambda:
extern PACCESS_TOKEN PsReferencePrimaryToken(IN PEPROCESS pProcess); // =
Assumption: Always returns a valid value that can be passed to ObDerference=
Token
extern void ObDereferenceObject(PVOID pObject); // =
Generic deleter
auto pToken =3D std::make_scoped_resource(PsReferencePrimaryToken(PsGetCurr=
entProcess()), [](PACCESS_TOKEN pToken) ->void
{
if(pToken =3D=3D nullptr)
{
syslog << "Warning, closing nullptr primary token on scope-ex=
it!!!";
}
ObDereferenceObject(pToken);
});
//
// Using bind
extern void * VirtualAllocGuaranteed(PVOID pPreferredBaseAddr, size_t szSiz=
e, unsigned int flags, unsigned int pageProtection); // System API that al=
ways returns usable pointer (even if nullptr / page zero)
extern void VirtualFree(void *pAddress, size_t size, unsigned int freeFlags=
); // Generic System API for releasing, freeing, etc. virtual memory
auto pVirtMem =3D std::make_scoped_resource(VirtualAllocGuaranteed(nullptr,=
4096, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE),
std::bind(VirtualFree, _1, 0, MEM_RELEASE));
</pre></code>
</p>
<h4>20.14.2.2 scoped_resource_unchecked's destructor</h4>
The <code>scoped_resource_unchecked</code> destructor will invoke the "dele=
ter" function object passed to the constructor, passing it the=20
tracked resource, as long as the <code>scoped_resource_unchecked</c=
ode> has not been "released" via a call to <code>release()</code>, or <code=
>invoke(true)</code>. By this means the resource clean-up is carried out b=
y the "deleter" function on scope-exit or unwind.
<h4>20.14.2.3 scoped_resource_unchecked's modifiers</h4>
<ul>
<li><code>release()</code> prevents the <code>scoped_resource_unchecked</co=
de> from=20
invoking the "deleter" function in the destructor. It return=
s a copy of the resource so that it may if needed, be assigned to another t=
racking object.</li>
<li><code>reset(resource)</code> causes the <code>scoped_resource_unchecked=
</code> to invoke the "deleter" function for any currently tracked resource=
that has not been "released", and assigns a new resource to the <code>scop=
ed_resource_unchecked</code> to be tracked. The <code>scoped_resource_unch=
ecked</code> will be set to an "un-released" state when a new resource is a=
ssigned.</li>
<li><code>invoke(true)</code> performs an early (pre-destructor) invocation=
of the "deleter" function. The=20
<em>default</em> true parameter sets the <code>scoped_resource_unchecke=
d</code> to the "released" state so that the deleter function will not be i=
nvoked again when the destructor is called, unless the object is subsequent=
ly "reset."</li>
<li><code>invoke(false)</code> performs an early (pre-destructor) invocatio=
n of the "deleter" function. The false parameter leaves the <code>scoped_r=
esource_unchecked</code> in the "un-released" state so that the deleter fun=
ction <b>will</b> be invoked again when the destructor is called.</li>
<li><code>operator()()</code> performs an early (pre-destructor) invocation=
of the deleter function, the same as if <code>invoke(true)</code> had been=
called.</li>
</ul>
<h4>20.14.2.4 scoped_resource_unchecked's accessors</h4>
<ul>
<li><code>TRes get() const throw()</code> returns the resource being manage=
d by the <code>scoped_resource_unchecked</code> object.</li>=20
<li><code>operator TRes() const throw()</code> returns the resource being m=
anaged by the <code>scoped_resource_unchecked</code> object.</li>=20
<li><code>TRes operator->() const</code> returns the resource being mana=
ged by the <code>scoped_resource_unchecked</code> object.</li>
<li><code>TRes* operator&()</code> returns a pointer to the resource being =
managed by the <code>scoped_resource_unchecked</code> object, where the <co=
de>scoped_resouce_unchecked</code> has a private member of type <code>TRes<=
/code> such as <code>TRes m_resource;</code> which is returned from this ac=
cessor with <code>return &m_resource;</code></li>
<li><code>TDel& get_deleter()</code> returns a reference to the deleter fun=
ction.=20
This allows the caller to modify the deleter function if needed on a no=
n-const=20
object.</li>
<li><code>const TDel& get_deleter() const</code> returns a reference to the=
deleter=20
function.</li>
</ul>
<h4>20.14.2.5 <code>make_scoped_resource_unchecked</code></h4>
<code>make_scoped_resource_unchecked(resource, deleterfunc)</code> is used =
to generate a <code>scoped_resource_unchecked</code> object. =20
See the examples above in 20.14.2.1.
<h4>20.14.2.6 <code>make_scoped_resource</code></h4>
<code>make_scoped_resource(resource, deleterfunc)</code> is used to generat=
e a <code>scoped_resource_unchecked</code> object in a manner that is compa=
tible with the generation of a <code>scoped_resource</code> object. The di=
fference between the generator for a <code>scoped_resource_unchecked</code>=
object and the generator for a <code>scoped_resource</code> is that the <c=
ode>scoped_resource</code> requires a 3rd parameter that is used for validi=
ty checking prior to invoking the deleter function. Also, <code>scoped_res=
ource</code> can be controlled through template parameters to <code>throw f=
ailed_resource_initialization();</code> when it is constructed with a resou=
rce that matches the "no-delete" value.
<h3>20.14.3 Addition of <code>std::failed_resource_initialization exceptio=
n</code></h3>
It is necessary to add an exception to the standard library to be thrown wh=
en invalid resources are assigned (or passed to the constructor) of a <code=
>scoped_resource</code> or <code>unique_resource</code> object. The follow=
ing is an example implementation.
<pre>
<code>
namespace std
{
///////////////////////////////////////////////////////////////////////=
/////
// failed_resource_initialization
// An exception thrown when a no-delete value is passed to a scoped_res=
ource
// or unique_resource constructor, assignment, or reset IF the template
// arguments allow for throwing. Throwing is optional so that these cl=
asses
// may be used in environment where exception can not be handled (e.g.
// kernel drivers, etc.) In those cases the resource should be validat=
ed
// using .valid() prior to use.
///////////////////////////////////////////////////////////////////////=
/////
class failed_resource_initialization : public exception
{
public:
explicit failed_resource_initialization(const char * =3D nullptr) t=
hrow()
{
}
virtual const char * what() const throw()
{
return "resource initialization failed";
}
};
}
</code>
</pre>
<h3>20.14.4 Class template <code>scoped_resource</code></h3>
<table>
<tr><td>1</td><td>A <i>scoped_resource</i> is an object <i>s</i> that m=
anages a generic resource <i>r</i> such that a clean-up function, function =
object, or lambda, <i>f(r)</i> will be invoked when <i>s</i> is destroyed (=
e.g., when leaving block scope (6.7)), as long as the resource passes a val=
idity check.</td></tr>
<tr><td>2</td><td>The function object <i>f</i> managed by <code>scoped_=
resource<TDel,=20
TRes, const bool throw_on_init_failure =3D false></code> takes a=
single parameter of the type of the resource <i>r</i> so that <i>s</i> may=
invoke <i>f(r)</i> as <code>f(r);</code>, when <i>s</i> leaves the current=
scope=20
or is otherwise destructed.</td></tr>
<tr><td>3</td><td><i>f</i> may be a function pointer, functor, a callab=
le function as returned from <code>std::bind</code>, or a lambda, taking a =
single argument of the type of the resource.</td</tr>
<tr><td>4</td><td><i>r</i> may be accessed through cast operators as if=
it were of the type of the resource <i>r</i>.</td></tr>
<tr><td>5</td><td>Unlike scoped_resource_unchecked, <i>r</i> <b>is</b> =
compared to a "no-delete value" prior to the invocation of <code>f(r)</code=
>.</td></tr>
<tr><td>6</td><td>A <code>scoped_resource</code> may be generated (is i=
ntended to be generated) using <code>make_scoped_resource(r, f, nd)</code><=
/td></tr>
<tr><td>7</td><td>The 3rd template parameter, when true, allows the con=
structors to throw if the resource matches the "invalid" or "no-delete" val=
ue.</code></td></tr>
</table>
<code>
<pre>
namespace std
{
template<typename TDel, typename TRes, const bool throw_on_init_fail=
ure> class scoped_resource
{
public:
// 20.14.4.1 constructors
explicit scoped_resource(TDel&& arg, TRes&& resource, TRes no_delet=
e_value);
explicit scoped_resource(const TDel& arg, const TRes& resource, TRe=
s no_delete_value);
// 20.14.4.2 destructor
~scoped_resource();
// 20.14.4.3 modifiers
TRes release() throw();
scoped_resource& reset(TRes&& resource);
scoped_resource& reset(const TRes& resource);
scoped_resource& invoke(bool bRelease =3D true);
void operator()();
// 20.14.4.4 access
TRes get() const throw();
operator TRes() const throw();
TRes operator->() const;
TRes* operator&();
TDel& get_deleter();
const TDel& get_deleter() const;
// 20.14.4.5 validity checking
bool valid() const throw();
};
// 20.14.4.6 Default Generator Function
// Takes 3 parameters: The Resource, the Deleter, and a "invalid" or "n=
o-delete" value
template<typename TDel, typename TRes>
scoped_resource<TDel, TRes, false> make_scoped_resource(TRes reso=
urce, TDel deleter, TRes nodelete)
{
return scoped_resource<TDel, TRes, false>(std::move(deleter), =
std::move(resource), std::move(nodelete));
}
// 20.14.4.7 Generator Function for throw_on_init
template<bool t_throw_on_init_failure, typename T, typename R>
scoped_resource<T, R, t_throw_on_init_failure> make_scoped_resour=
ce(R r, T t, R nd)
{
return scoped_resource<T, R, t_throw_on_init_failure>(std::mov=
e(t), std::move(r), std::move(nd));
}
}
</pre>
</code>
<p>
<h4>20.14.4.1 scoped_resource constructors</h4>
The <code>scoped_resource</code> constructors take three arguments:
<ol>
<li>The deleter function - a callable function (or lambda) taking a single =
parameter of the type of the second template argument.</li>
<li>The resource to be managed / tracked by the <code>scoped_resource.</cod=
e>
<li>A no-delete or "invalid" value of the type of the resource which may be=
used for comparision to:
<ul>
<li>Prevent calling the deleter function in the destructor, when the resour=
ce has an invalid value (e.g. -1 for a file descriptor).</li>
<li>Allow a comparision for the valid() method.</li>
<li>Allow a comparision for when throwing an exception is enabled in the co=
nstructor when passed an invalid value.</li>
</ul>
</li>
</ol>It is intended that <code>std::make_scoped_resource(resource, deleter,=
nodelete)</code> be used to generate a <code>scoped_resource</code>, as in=
the following examples:
<code><pre>
//
// Most common usage - close "handle" types on scope-exit, using a function=
....
extern HANDLE CreateEventW(PSECURITY_ATTRIBUTES pEventAttributes, BOOL bMan=
ualReset, BOOL bInitialState, PCWSTR pName);
extern void CloseHandle(HANDLE h);
extern int open(const char *pszFilename, int oflags, ...);
extern void close(int iFileDesc);
// Construction via Generic Generator with nullptr check, no-throw option
auto hEvent =3D std::make_scoped_resource(CreateEvent(nullptr, FALSE, FALSE=
, nullptr), CloseHandle, nullptr);
if(hEvent.valid()) // After Initialization check if (hEvent =3D=3D nullptr)
//
// Construction via Generic Generator with nullptr check, throw on allocati=
on failure...
try
{
auto hEvent =3D std::make_scoped_resource<true>(CreateEvent(nullp=
tr, FALSE, FALSE, nullptr), CloseHandle, nullptr);
}
catch (const std::failed_resource_initialization &e)
{
// Deal with failure to CreateEvent, IOW hEvent =3D=3D nullptr
}
//
// Construction via Generic Generator with -1 check, no-throw option
auto iFileDesc =3D std::make_scoped_resource(open("/tmp/log.txt", O_WRONLY|=
O_APPEND), close, -1);
if(iFileDesc.valid()) // Check validity
{
write(iFileDesc, ...);
}
//
// Construction via Generic Generator with -1 check, throw on allocation fa=
ilure
try
{
auto iFileDesc =3D std::make_scoped_resource<true>(open("/tmp/log=
..txt", O_WRONLY|O_APPEND), close, -1);
write(iFileDesc, ...); // Can't get here if allocation failed
}
catch (const std::failed_resource_initialization &e)
{
// Deal with failure to open file, IOW iFileDesc =3D=3D -1
}
</pre></code>
Note: Manual constuction is also possible with <code>scoped_resource</code>=
in much the same way as with <code>scoped_resource_unchecked</code>. Also=
, leaving the decision on whether to throw, or require testing for allocati=
on failures up to the user makes it possible to use <code>scoped_resource</=
code> in places, such as kernel-mode code, where exceptions can not be tole=
rated.
</p>
<h4>20.14.4.2 scoped_resource_unchecked's destructor</h4>
The <code>scoped_resource</code> destructor will invoke the "deleter" funct=
ion object passed to the constructor, passing it the tracked resource, as l=
ong as the <code>scoped_resource</code> has not been "released" via a call =
to <code>release()</code>, or <code>invoke(true)</code>, and if the resourc=
e does not match the no-delete value. By this means the resource clean-up =
is carried out by the "deleter" function on scope-exit or unwind.
<h4>20.14.4.3 scoped_resource's modifiers</h4>
<ul>
<li><code>release()</code> prevents the <code>scoped_resource</code> from i=
nvoking the "deleter" function in the destructor. It returns a c=
opy of the resource so that if needed it may be assigned to a new tracking =
object, such as a <code>scoped_resource</code> within a different scope.</l=
i>
<li><code>reset(resource)</code> causes the <code>scoped_resource</code> to=
invoke the "deleter" function for any currently tracked <i>and valid</i> r=
esource that has not been "released", and assigns a new resource to the <co=
de>scoped_resource</code> to be tracked. The <code>scoped_resource</code> =
will be set to the "un-released" state when a new resource is assigned. Th=
e deleter function does not change. If the <code>scoped_resource</code> wa=
s constructed with the throw-option, the new resource will be compared to t=
he no-delete value passed to the constructor and <code>std::failed_resource=
_initialization</code> exception will be thrown if it matches.</li>
<li><code>invoke(true)</code> performs an early (pre-destructor) invocation=
of the "deleter" function <i>for a valid resource</i>. The <em>default</e=
m> true parameter sets the <code>scoped_resource</code> to the "released" s=
tate so that the deleter function will not be invoked again when the destru=
ctor is called, unless the object is subsequently "reset."</li>
<li><code>invoke(false)</code> performs an early (pre-destructor) invocatio=
n of the "deleter" function <i>for a valid resource</i>. The false paramet=
er leaves the <code>scoped_resource</code> in the "un-released" state so th=
at the deleter function <b>will</b> be invoked again when the destructor is=
called.</li>
<li><code>operator()()</code> performs an early (pre-destructor) invocation=
of the deleter function, the same as if <code>invoke(true)</code> had been=
called.</li>
</ul>
<h4>20.14.4.4 scoped_resource accessors</h4>
<ul>
<li><code>TRes get() const throw()</code> returns the resource being manage=
d by the <code>scoped_resource</code> object.</li>=20
<li><code>operator TRes() const throw()</code> returns the resource being m=
anaged by the <code>scoped_resource</code> object.</li>=20
<li><code>TRes operator->() const</code> returns the resource being mana=
ged by the <code>scoped_resource</code> object.</li>
<li><code>TRes* operator&()</code> returns a pointer to the resource being =
managed by the <code>scoped_resource</code> object, where the <code>scoped_=
resouce</code> has a private member of type <code>TRes</code> such as <code=
>TRes m_resource;</code> which is returned from this accessor with <code>re=
turn &m_resource;</code></li>
<li><code>TDel& get_deleter()</code> returns a reference to the deleter fun=
ction. This allows the caller to modify the deleter function if needed on a=
non-const object.</li>
<li><code>const TDel& get_deleter() const</code> returns a reference to the=
deleter function.</li>
</ul>
<h4>20.14.4.5 scoped_resource validity checking</h4>
The <code>valid()</code> member may be used to compare the tracked resource=
to the no-delete value used when constructing the <code>scoped_resource</c=
ode> object. It returns true if the resource is NOT equal to the no-delete=
value.
<h4>20.14.4.6 <code>make_scoped_resource - Default Generator Function</code=
></h4>
<code>make_scoped_resource_unchecked(resource, deleterfunc, no_delete_value=
)</code> is used to generate a <code>scoped_resource</code> object. Se=
e the examples above in 20.14.3.1.
The absence of the true bool template parameter indicates that an exception=
should NOT be thrown if the tracked resource is assigned a value equal to =
the no_delete_value, or in other words, <code>if(resource =3D=3D no_delete_=
value)</code>. In this case the user is responsible for checking the valid=
ity of the resource via the <code>valid()</code> member function. This all=
ows <code>scoped_resource</code> to be used in enviroments (such as kernel-=
mode code) where exceptions can not be tolerated.
<h4>20.14.4.7 <code>make_scoped_resource<true> - Generator Function w=
hich allows throws on allocation failure</code></h4>
<code>make_scoped_resource_unchecked<bool>(resource, deleterfunc, no_=
delete_value)</code> is used to generate a <code>scoped_resource</code> obj=
ect. See the examples above in 20.14.3.1.
The bool template parameter indicates whether or not a <code>std::failed_re=
source_initialization</code> exception should be thrown if the tracked reso=
urce is assigned a value equal to the no_delete_value, or in other words:<b=
r/>
<code>if(resource =3D=3D no_delete_value)</code>.
<h3>20.14.5 Class template <code>unique_resource</code></h3>
<table>
<tr><td>1</td><td>A <i>unique_resource</i> is an object <i>s</i> that m=
anages a generic resource <i>r</i> such that a <i>static</i> clean-up funct=
ion, <i>f(r)</i> will be invoked when <i>s</i> is destroyed (e.g., when lea=
ving block scope (6.7)), as long as the resource passes a validity check.</=
td></tr>
<tr><td>2</td><td>The clean-up function <i>f</i> managed by <code>uniqu=
e_resource</code> takes a single parameter of the type of the resource <i>r=
</i> so that <i>s</i> may invoke <i>f(r)</i> as <code>f(r);</code>, when <i=
>s</i> leaves the current scope=20
or is otherwise destructed.</td></tr>
<tr><td>3</td><td><i>f</i> must be a function that can be passed and in=
voked as a template argument, known at compile time. The no-delete value m=
ust also be a static value that may be passed and evaluated as a template a=
rgument. This allows the compiler to generate the least possible amount of=
code for each <code>unique_resource</code>.</td</tr>
<tr><td>4</td><td><i>r</i> may be accessed through cast operators as if=
it were of the type of the resource <i>r</i>.</td></tr>
<tr><td>5</td><td>Like scoped_resource, <i>r</i> <b>is</b> compared to =
a "no-delete value" prior to the invocation of <code>f(r)</code>.</td></tr>
<tr><td>6</td><td>There is no generator for <code>unique_resource</code=
>. It is designed for use in places where a generator is not convenient, a=
nd where the smallest generated code possible is needed.</td></tr>
<tr><td>7</td><td>The 3rd template parameter, when true, allows the con=
structors to throw if the resource matches the "invalid" or "no-delete" val=
ue.</code></td></tr>
<tr><td>8</td><td>Convenience macros are provided to simplify the decla=
ration of template parameters.</code></td></tr>
<tr><td>9</td><td>As shown below, the reference implementation uses an =
implementation-defined class and a set of implementation defined helper cla=
sses to aid in deducing template parameters. While these classes are not p=
art of the specification, the interfaces they expose must be carried forwar=
d to the actual <code>unique_resource</code> implementation which in this c=
ase inherits from the base class.</td></tr>
</table>
<code>
<pre>
namespace std
{
// 20.14.5.1 unique_resource_impl
template<typename TResource, typename TDeleter, TDeleter t_deleter, =
bool throw_on_init_failure, TResource t_nodelete>
class unique_resource_impl
{
private:
unique_resource_impl(const unique_resource_impl &);
void operator=3D(const unique_resource_impl &);
public:
unique_resource_impl() : m_resource(t_nodelete) // Allows for op=
erator=3D(TResource) later...
{
}
explicit unique_resource_impl(TResource&& resource) : m_resource(st=
d::move(resource))
{
if(throw_on_init_failure && t_nodelete =3D=3D m_resource)
{
throw failed_resource_initialization();
}
}
explicit unique_resource_impl(const TResource& resource) : m_resour=
ce(resource)
{
if(throw_on_init_failure && t_nodelete =3D=3D m_resource)
{
throw failed_resource_initialization();
}
}
~unique_resource_impl()
{
invoke(true);
}
TResource release() throw()
{
TResource tempcopy =3D m_resource;
m_resource =3D t_nodelete;
return tempcopy;
}
unique_resource_impl& reset(TResource&& resource)
{
invoke(false); // false because we are going to change i=
t manually here...
m_resource =3D std::move(resource);
if(throw_on_init_failure && t_nodelete =3D=3D m_resource)
{
throw failed_resource_initialization();
}
return *this;
}
unique_resource_impl& reset(TResource const& resource)
{
invoke(false); // false because we are going to change i=
t manually here...
m_resource =3D resource;
if(throw_on_init_failure && t_nodelete =3D=3D m_resource)
{
throw failed_resource_initialization();
}
return *this;
}
void operator()()
{
invoke(true);
}
TResource get() const throw()
{
return m_resource;
}
void operator=3D(TResource &&res)
{
reset(res);
}
void operator=3D(TResource const &res)
{
reset(res);
}
//
// Cast operator - for access to resource
// WARNING: This can cause make_scoped_resource*(R, T) to return a =
temporary that initializes something else! Be careful with usage!
// Nevertheless, it provides transparency for API calls, etc.
operator TResource() const throw()
{
return m_resource;
}
//
// operator-> for accessing members on pointer types
TResource operator->() const
{
return m_resource;
}
//
// operator& for getting the address of the resource - not const!
TResource* operator&()
{
return &m_resource;
}
const TDeleter get_deleter() const
{
return t_deleter;
}
//
// invoke...(e.g. early invocation), allows for repeated
// invocation, if bRelease =3D false. Use with caution!
unique_resource_impl& invoke(bool bRelease =3D true)
{
if(valid())
{
t_deleter(m_resource);
if(bRelease)
{
m_resource =3D t_nodelete;
}
}
return *this;
}
//
// Check for a valid / usable resource
bool __inline valid() const throw()
{
return m_resource !=3D t_nodelete;
}
};
// 20.14.5.2 implementation specific helper classes used to deduce temp=
late parameters
//
// Extract First Parameter Type
//
template <typename T>
struct TFuncInfo1;
#if defined(_WIN32) && !defined(_WIN64) // Support Microsoft cal=
ling conventions
template <typename TReturn, typename TParam>
struct TFuncInfo1<TReturn (__stdcall *)(TParam)>
{
typedef TReturn tReturnType;
typedef TParam tParameter1;
};
template <typename TReturn, typename TParam>
struct TFuncInfo1<TReturn (__cdecl *)(TParam)>
{
typedef TReturn tReturnType;
typedef TParam tParameter1;
};
template <typename TReturn, typename TParam>
struct TFuncInfo1<TReturn (__fastcall *)(TParam)>
{
typedef TReturn tReturnType;
typedef TParam tParameter1;
};
#else // All other compilers
template <typename TReturn, typename TParam>
struct TFuncInfo1<TReturn (*)(TParam)>
{
typedef TReturn tReturnType;
typedef TParam tParameter1;
};
#endif // _WIN32 && !_WIN64
// 20.14.5.3 unique_resource (reference implementation)
template<typename TDeleter,
TDeleter t_deleter,
bool throw_on_init_failure =3D false, // Set to true if you =
want throw(failed_resource_initialization) when m_resource =3D=3D t_nodelet=
e_value
typename TFuncInfo1<TDeleter>::tParameter1 t_nodelete_value =
=3D static_cast<typename TFuncInfo1<TDeleter>::tParameter1>(nul=
lptr)>
struct unique_resource : public
unique_resource_impl<typename TFuncInfo1<TDeleter>::tParam=
eter1, TDeleter, t_deleter, throw_on_init_failure, t_nodelete_value>=20
{
typedef typename TFuncInfo1<TDeleter>::tParameter1 TResource;
unique_resource() :=20
unique_resource_impl<typename TFuncInfo1<TDeleter>::tP=
arameter1, TDeleter, t_deleter, throw_on_init_failure, t_nodelete_value>=
()
{
}
unique_resource(TResource &&resource) :=20
unique_resource_impl<typename TFuncInfo1<TDeleter>::tP=
arameter1, TDeleter, t_deleter, throw_on_init_failure, t_nodelete_value>=
(std::move(resource))
{
}
unique_resource(TResource const &resource) :=20
unique_resource_impl<typename TFuncInfo1<TDeleter>::tP=
arameter1, TDeleter, t_deleter, throw_on_init_failure, t_nodelete_value>=
(resource)
{
}
void operator=3D(TResource &&resource)
{
this->reset(resource);
}
void operator=3D(TResource const &resource)
{
this->reset(resource);
}
};
//
// 20.14.5.4 unique_resource (specification)
template<typename TDeleter,
TDeleter t_deleter,
bool throw_on_init_failure =3D false, // Set to true if you =
want throw(failed_resource_initialization) when m_resource =3D=3D t_nodelet=
e_value
typename TFuncInfo1<TDeleter>::tParameter1 t_nodelete_value =
=3D static_cast<typename TFuncInfo1<TDeleter>::tParameter1>(nul=
lptr)>
class unique_resource=20
{
typedef typename TFuncInfo1<TDeleter>::tParameter1 TResource;
// 20.14.5.4.1 - unique_resource constructors
unique_resource();
unique_resource(TResource &&resource);
unique_resource(TResource const &resource);
// 20.14.5.4.2 - unique_resource destructor
~unique_resource();
// 20.14.5.4.3 - unique_resource modifiers
TResource release() throw();
unique_resource_impl& reset(TResource&& resource);
unique_resource_impl& reset(TResource const& resource);
unique_resource_impl& invoke(bool bRelease =3D true);
void operator()();
void operator=3D(TResource &&resource);
void operator=3D(TResource const &resource);
// 20.14.5.4.4 - unique_resource accessors
TResource get() const throw();
operator TResource() const throw();
TResource operator->() const;
TResource* operator&();
const TDeleter get_deleter() const;
// 20.14.5.4.5 - unique_resource validity checking
bool __inline valid() const throw();
};
//
// 20.14.5.5 Helper Macros
// The following macros simplify template parameters for unique_resourc=
e
#define UNIQUE_DELETER(deleter_fn) decltype(&deleter_fn), deleter_fn, f=
alse
#define UNIQUE_DELETER_THROW(deleter_fn) decltype(&deleter_fn), deleter=
_fn, true
#define UNIQUE_DELETER_NOTHROW(deleter_fn) decltype(&deleter_fn), delet=
er_fn, false
}
</pre>
</code>
<p>
<h4>20.14.5.1 The Reference Implementation - <code>unique_resource_impl</co=
de></h4>
The reference implementation is shown above to provide insight on the inten=
ded design of <code>unique_resource</code> with its implementation specific=
classes the accomodate template deduction. All code shown in the referenc=
e implementation is provided as an example only and not part of an official=
specification. Each actual implemenation will need to supply it's own met=
hods of providing adequate template deduction methods to support constructi=
on of a <code>unique_resource</code> as shown in section 20.14.5.4.1.
<h4>20.14.5.2 Helper Classes</h4>
The classes and template metaprogramming shown here is also provided only a=
s an example so that the definition provided in section 20.14.5.4 makes sen=
se. These helper classes are implementation specific and are used to allow=
automatic deducing of the type of the resource being tracked by <code>uniq=
ue_resource</code>. An implementation that can satisify the construction s=
pecification shown in section 20.14.5.4.1 below may or may not need these h=
elper classes (specifically) <code>TFuncInfo</code>.
<h4>20.14.5.3 The Reference Implentation - <code>unique_resource</code></h4=
>
The reference implementation is shown above to provide insight on the inten=
ded design of <code>unique_resource</code> and how it utilizes template met=
aprogramming to deduce template arguments for the construction of <code>uni=
que_resource</code> and it's implementation specific base class <code>uniqu=
e_resource_impl</code> (20.14.5.1) to satisify the construction specificati=
ons laid out in section 20.14.5.4.1.
<h4>20.14.5.4 <code>unique_resource</code></h4>
<h5>20.14.5.4.1 <code>unique_resource</code> construction</h5>
<code>unique_resource</code> may be constructed using one (1) or zero (0) a=
rguments. This is possible because the template parameters supplied provid=
e a deleter function used to clean-up the resource on <code>unique_resource=
</code> destruction. A zero parameter constructor creates an object that h=
as no resource to track until a subsequent assignment or reset.
Template Parameters:
<ol>
<li>The <i>type</i> of the deleter function - a function taking a single pa=
rameter of the <i>type</i> of the resource being tracked. The resource <i>=
type</i> is deduced from the argument to the deleter function.</li>
<li>The deleter function itself. A static value that is known at compile t=
ime and can be expressed as a template parameter and invoked in the destruc=
tor by passing the tracked resource as the solitary parameter.</li>
<li>A bool value indicating whether or not the constructor or assignment op=
erator should throw <code>std::failed_resource_initialization</code> if the=
resource is assigned (or constructed with) a value matching the no-delete =
or "invalid" value. The no-delete value must be of the <i>type</i> of the =
resource which is deduced from the argument required by the deleter functio=
n.</li>
<li>A no-delete or "invalid" value of the <i>type</i> of the resource being=
tracked. This parameter defaults to <code>nullptr</code> after having bee=
n cast (<code>static_cast</code> to the <i>type</i> of the resource.) The =
no-delete value must be a static value known at compile time that may be pa=
ssed as a template parameter and used in a comparison withing the invoke() =
method or the destructor.</li>
</ol>
</br>
<code>unique_resource</code> is meant to be used in places where:
<ul>
<li><code>make_scoped_resource()</code> is unsuitable or awkward, such as i=
s the case for class member variables that can not be declared as <code>aut=
o</code>.</li>
<li>Where very small (tight) code generation is desired, since the deleter =
function and no-delete value are static values that <i>should not</i> be st=
ored in member variables.</li>
</ul>
</br>
The following are examples of <code>unique_resource</code> objects being co=
nstructed:
<code><pre>
//
// Most common usage - close "handle" types on scope-exit or class destruct=
ion...
extern HANDLE OpenFileW(const wchar_t *pwzFilename);
extern HANDLE CreateEventW(PSECURITY_ATTRIBUTES pEventAttributes, BOOL bMan=
ualReset, BOOL bInitialState, PCWSTR pName);
extern void SetEvent(HANDLE hEvent);
extern void CloseHandle(HANDLE h);
extern int open(const char *pszFilename, int oflags, ...);
extern void close(int iFileDesc);
extern ssize_t pwrite(int iFileDes, const void *pBuf, size_t szBytes, off_t=
offset);
class MyDataFile
{
private:
const std::unique_resource<UNIQUE_DELETER(CloseHandle)> m_hWriteS=
ignaledEvent; // NOTE: Using helper macro
std::unique_resource<decltype(&CloseHandle), CloseHandle, INVALID_HA=
NDLE_VALUE> m_hFile; // NOTE: Not using helper macro, also with non-def=
ault no-delete value
std::unique_resource<UNIQUE_DELETER_NOTHROW(SetEvent)> hSignalThr=
ead; // NOTE: In this case we only want a .valid() even=
t handle if it is created/assigned later - using default constructor
std::vector<unsigned char> m_vData;
public:
MyDataFile(const wchar_t *pwzFileName) :
m_hWriteSignaledEvent(CreateEvent(nullptr, FALSE, FALSE, nullptr)),=
// Note, very simple construction
m_hFile(OpenFileW(pwzFileName)) =
// Notice that we let m_hSignalThread use the default constructor, it=
starts with .valid() =3D=3D false
{
}
.
.
.
void SetEventToSignalOnClassDestruction(HANDLE hEvent)
{
m_hSignalThread =3D hEvent; // Contrived example, but sho=
wing assignment operator after default construction...
// When this class is destroyed, the event handle will be passed to=
SetEvent. Also happens to an existing event handle prior to assignment of=
a new value.
}
DWORD WriteOnSignal()
{
DWORD dwWait =3D WaitForSingleObject(m_hWriteSignaledEvent, INFINIT=
E);
if(false =3D=3D m_hFile.valid()) // Use validation method
{
return;
}
DWORD dwWritten =3D 0;
if(WAIT_OBJECT_O =3D=3D dwWait)
{
WriteFile(m_hFile, &m_vData, m_vData.size(), &dwWritten, nullpt=
r);
}
return dwWritten;
}
};
//
// Example using throw option...
void DumpVector(const char *pszFilename, std::vector<unsigned char> &=
vBuffer, off_t where)
{
try
{
std::unique_resource<UNIQUE_DELETER_THROW(close, -1)> iFileDe=
sc(open(pszFilename, O_RDWR|O_APPEND));
if(pwrite(iFileDesc, &vBuffer[0], vBuffer.size(), where) !=3D vBuff=
er.size())
{
throw write_failed; // example, not defined here...
}
}
catch (const std::failed_resource_initialization &e)
{
// Deal with error (file open failed) condition!
}
}
</pre></code>
</p>
<h5>20.14.5.4.2 unique_resource's destructor</h5>
The <code>unique_resource</code> destructor will invoke the "deleter" funct=
ion object supplied as a template parameter, passing it the tracked resourc=
e, as long as the <code>unique_resource</code> has not been "released" via =
a call to <code>release()</code>, or <code>invoke(true)</code>, and does no=
t match the no-delete value. By this means the resource clean-up is carrie=
d out by the "deleter" function on scope-exit or unwind.
<h5>20.14.5.4.3 unique_resource's modifiers</h5>
<ul>
<li><code>release()</code> prevents the <code>unique_resource</code> from i=
nvoking the "deleter" function in the destructor, by assigning th=
e no-delete value to the internally tracked resource. Returns a copy of th=
e resource so that if needed it may be assigned to another tracking object,=
such as a <code>unique_resource</code> in another instance of a class (e.g=
.. in a copy constructor).</li>
<li><code>reset(resource)</code> causes the <code>unique_resource</code> to=
invoke the "deleter" function for any currently tracked <i>and valid</i> r=
esource that has not been "released", and assigns a new resource to the <co=
de>unique_resource</code> to be tracked. The <code>unique_resource</code> =
will be set to the "un-released" state when a new resource is assigned. Th=
e deleter function does not change. If the <code>unique_resource</code> wa=
s constructed with the throw-option, the new resource will be compared to t=
he no-delete value passed to the constructor and <code>std::failed_resource=
_initialization</code> exception will be thrown if it matches.</li>
<li><code>invoke(true)</code> performs an early (pre-destructor) invocation=
of the "deleter" function <i>for a valid resource</i>. The <em>default</e=
m> true parameter sets the <code>unique_resource</code> to the "released" s=
tate so that the deleter function will not be invoked again when the destru=
ctor is called, unless the object is subsequently "reset."</li>
<li><code>invoke(false)</code> performs an early (pre-destructor) invocatio=
n of the "deleter" function <i>for a valid resource</i>. The false paramet=
er leaves the <code>unique_resource</code> in the "un-released" state so th=
at the deleter function <b>will</b> be invoked again when the destructor is=
called.</li>
<li><code>operator()()</code> performs an early (pre-destructor) invocation=
of the deleter function <i>for a valid resource</i>, the same as if <code>=
invoke(true)</code> had been called.</li>
<li><code>operator=3D(TResource &&res)</code> performs an early (pre-destru=
ctor) invocation of the deleter function <i>for a valid, assigned resource<=
/i>, and assigns a tracks a new resource the same as if <code>reset(res)</c=
ode> had been called.</li>
<li><code>operator=3D(TResource const &res)</code> performs an early (pre-d=
estructor) invocation of the deleter function <i>for a valid, assigned reso=
urce</i>, and assigns a tracks a new resource the same as if <code>reset(re=
s)</code> had been called.</li>
</ul>
<h5>20.14.5.4.4 unique_resource accessors</h5>
<ul>
<li><code>TResource get() const throw()</code> returns the resource being m=
anaged by the <code>unique_resource</code> object.</li>=20
<li><code>operator TResource() const throw()</code> returns the resource be=
ing managed by the <code>unique_resource</code> object.</li>=20
<li><code>TResource operator->() const</code> returns the resource being=
managed by the <code>unique_resource</code> object.</li>
<li><code>TResource* operator&()</code> returns a pointer to the resource b=
eing managed by the <code>unique_resource</code> object, where the <code>un=
ique_resource</code> has a private member of type <code>TResource</code> su=
ch as <code>TResource m_resource;</code> which is returned from this access=
or with <code>return &m_resource;</code></li>
<li><code>const TDeleter& get_deleter() const</code> returns a reference to=
the deleter function. The deleter function can not be modified.</li>
</ul>
// 20.14.5.4.5 - unique_resource validity checking
bool __inline valid() const throw();
<h5>20.14.5.4.5 unique_resource validity checking</h5>
The <code>valid()</code> member may be used to compare the tracked resource=
to the no-delete value specified in the template parameters. It returns t=
rue if the resource is NOT equal to the no-delete value.
<h4>20.14.5.5 Helper Macros</h4>
The following helper macros are defined to simplify the passing of template=
parameters for <code>unique_resource</code>:
<ul>
<li><code>UNIQUE_DELETER(delter_fn)</code> - supplies the <i>type of</i> th=
e deleter function, and the deleter function parameters, supplying false fo=
r the throw option.</li>
<li><code>UNIQUE_DELETER_THROW(delter_fn)</code> - supplies the <i>type of<=
/i> the deleter function, and the deleter function parameters, supplying tr=
ue for the throw option.</li>
<li><code>UNIQUE_DELETER_NOTHROW(delter_fn)</code> - supplies the <i>type o=
f</i> the deleter function, and the deleter function parameters, supplying =
false for the throw option.</li>
</ul>
For usage examples please see section 20.14.5.4.1. Use of the macros is no=
t a requirement. They are provided only to simplify declaration of an othe=
rwise long list of parameters.
<h2>VII. Acknowledgements</h2>
<ul>
<li>Special thanks and recognition to those on both the Boost Developer mai=
ling list and the ISO C++ std-proposal mailing list for advancing the desig=
n of the classes presented in this proposal and for general encouragement!&=
nbsp;=20
Also, recognition is due to <a href=3D"http://www.openspan.com/">OpenSp=
an, Inc</a>.=20
for supporting the production of this proposal and for early adoption a=
nd=20
testing of the reference implementation and prior implementations of th=
e=20
proposal in real world (and for that matter world class) products.</li>
</ul>=20
<h2>VIII. Reference Implemenation</h2>
A <a href=3D"http://www.andrewlsandoval.com/scope_exit/scoped_resource.h">r=
eference implementation</a> may be viewed, downloaded, and used from <a hre=
f=3D"http://www.andrewlsandoval.com/scope_exit/scoped_resource.h">http://ww=
w.andrewlsandoval.com/scope_exit/scoped_resource.h</a>.
<h2>IX. References</h2>
<ol>
<a name=3D"reference1"><li><a href=3D"http://www.boost.org/doc/libs/1_52_0/=
libs/scope_exit/doc/html/scope_exit/alternatives.html">Boost.org, Boost Sco=
pe.Exit: Annex - Alternatives</a></li></a>
<a name=3D"reference2"><li><a href=3D"http://www.drdobbs.com/cpp/generic-ch=
ange-the-way-you-write-excepti/184403758">Dr. Dobbs Magazine, <u>Change the=
Way You Write Exception-Safe Code =97 Forever</u>, Andrei Alexandrescu and=
Petru Marginean, December 01, 2000</a></li>
</ol>
</BODY>
</HTML>
------=_Part_130_30204036.1366808910090--
.
Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@gmail.com>
Date: Wed, 24 Apr 2013 15:13:12 +0200
Raw View
2013/4/24 Andrew Sandoval <sandoval@netwaysglobal.com>:
> The last time I sent this out to the group it was overshadowed by the
> meetings in Bristol. I've also sent this to lwgchair requesting a document
> number but have not yet received a number. I don't know if this is because
> I've not properly formatted the specification section, or if there is just
> more work than time for lwgchair, but either way I would appreciate
> feedback.
There was just no time for lwgchair during the last week. Document
number allocation will happen soon (If you have changed your title,
please inform lwgchair soon).
- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
.