Topic: Questions about N3949 - Scoped Resource - Generic
Author: Adi Shavit <adishavit@gmail.com>
Date: Sun, 31 Aug 2014 07:03:18 -0700 (PDT)
Raw View
------=_Part_146_320931048.1409493798857
Content-Type: text/plain; charset=UTF-8
Hi,
It is often useful to have resources as members of a class to be cleaned
upon destruction (this is what RAII is all about!).
However, to declare a member of scoped_resource in the class header, I
would need to know the type of the deleter (as opposed to, e.g. shared_ptr
which does not require this).
I guess I could use decltype in the member type definition, but that would
require stating the actual deleter at 2 different places: header + the
initialization.
All the examples I saw use 'auto' for local scope, but AFAIK, you cannot
use auto in the class declaration since the size needs to be known at
compile time.
Am I missing something here or is this by design?
What is the rational for this and how would one a succinct scoped_resource
declaration?
Warm regards,
Adi
--
---
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/.
------=_Part_146_320931048.1409493798857
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Hi,<div><br></div><div> It is often useful to have r=
esources as members of a class to be cleaned upon destruction (this is what=
RAII is all about!).</div><div>However, to declare a member of scoped_reso=
urce in the class header, I would need to know the type of the deleter (as =
opposed to, e.g. shared_ptr which does not require this).</div><div>I guess=
I could use decltype in the member type definition, but that would require=
stating the actual deleter at 2 different places: header + the initializat=
ion.</div><div><br></div><div>All the examples I saw use 'auto' for local s=
cope, but AFAIK, you cannot use auto in the class declaration since the siz=
e needs to be known at compile time.</div><div>Am I missing something here =
or is this by design?</div><div>What is the rational for this and how would=
one a succinct scoped_resource declaration?</div><div><br></div><div>Warm =
regards,</div><div>Adi</div><div> </div></div>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_146_320931048.1409493798857--
.
Author: David Krauss <potswa@gmail.com>
Date: Sun, 31 Aug 2014 23:26:44 +0800
Raw View
--Apple-Mail=_AC6BF572-F08A-453E-B867-FAB5391CBDE0
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1
On 2014-08-31, at 10:03 PM, Adi Shavit <adishavit@gmail.com> wrote:
> Am I missing something here or is this by design?
> What is the rational for this and how would one a succinct scoped_resourc=
e declaration?
The difference between type-erased shared_ptr and fully-static unique_ptr, =
and its cousin scoped_resource, is an indirect function call. This is neces=
sary because a shared_ptr can almost never expect to know the dynamic type =
of the object it retains, but most unique_ptr use cases statically know the=
dynamic type.
The solution is to add your own indirect call into the deleter, such as by =
using a naked function pointer pointer type as the deleter, or by virtual o=
perator ().
For what it's worth, I'm not convinced that scoped_resource provides any us=
eful encapsulation. Simply writing a class with a destructor is more terse =
and more expository. Virtual destructors are among the most widely-known id=
ioms in existence, and simply "doing things the old-fashioned way" would li=
kely have avoided this deleter confusion entirely.
--=20
---=20
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 e=
mail 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-proposa=
ls/.
--Apple-Mail=_AC6BF572-F08A-453E-B867-FAB5391CBDE0
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=ISO-8859-1
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dwindows-1252"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-=
mode: space; -webkit-line-break: after-white-space;"><br><div><div>On 2014&=
ndash;08–31, at 10:03 PM, Adi Shavit <<a href=3D"mailto:adishavit@=
gmail.com">adishavit@gmail.com</a>> wrote:</div><br class=3D"Apple-inter=
change-newline"><blockquote type=3D"cite"><div dir=3D"ltr"><div>Am I missin=
g something here or is this by design?</div><div>What is the rational for t=
his and how would one a succinct scoped_resource declaration?</div></div></=
blockquote><div><br></div><div>The difference between type-erased <font fac=
e=3D"Courier">shared_ptr</font> and fully-static <font face=3D"Courier">uni=
que_ptr</font>, and its cousin <font face=3D"Courier">scoped_resource</font=
>, is an indirect function call. This is necessary because a <font face=3D"=
Courier">shared_ptr</font> can almost never expect to know the dynamic type=
of the object it retains, but most <font face=3D"Courier">unique_ptr<=
/font> use cases statically know the dynamic type.</div><div><br></div=
><div>The solution is to add your own indirect call into the deleter, such =
as by using a naked function pointer pointer type as the deleter, or by <fo=
nt face=3D"Courier">virtual operator ()</font>.</div><div><br></div><div>Fo=
r what it’s worth, I’m not convinced that <font face=3D"Courier=
">scoped_resource</font> provides any useful encapsulation. Simply writing =
a class with a destructor is more terse and more expository. Virtual destru=
ctors are among the most widely-known idioms in existence, and simply &ldqu=
o;doing things the old-fashioned way” would likely have avoided this =
deleter confusion entirely.</div><div><br></div></div></body></html>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_AC6BF572-F08A-453E-B867-FAB5391CBDE0--
.
Author: David Krauss <potswa@gmail.com>
Date: Sun, 31 Aug 2014 23:29:10 +0800
Raw View
--Apple-Mail=_E2B78C6D-4455-4FE5-8B90-322E87B61853
Content-Type: text/plain; charset=ISO-8859-1
On 2014-08-31, at 11:26 PM, David Krauss <potswa@gmail.com> wrote:
> such as by using a naked function pointer pointer
Sorry, I stuttered. Only one pointer please.
--
---
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/.
--Apple-Mail=_E2B78C6D-4455-4FE5-8B90-322E87B61853
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=ISO-8859-1
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dwindows-1252"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-=
mode: space; -webkit-line-break: after-white-space;"><br><div><div>On 2014&=
ndash;08–31, at 11:26 PM, David Krauss <<a href=3D"mailto:potswa@g=
mail.com">potswa@gmail.com</a>> wrote:</div><br class=3D"Apple-interchan=
ge-newline"><blockquote type=3D"cite"><div style=3D"font-family: Helvetica;=
font-size: 12px; font-style: normal; font-variant: normal; font-weight: no=
rmal; letter-spacing: normal; line-height: normal; orphans: auto; text-alig=
n: start; text-indent: 0px; text-transform: none; white-space: normal; wido=
ws: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">such as by us=
ing a naked function pointer pointer</div></blockquote><div><br></div></div=
>Sorry, I stuttered. Only one pointer please.<div><div><br></div></div></bo=
dy></html>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_E2B78C6D-4455-4FE5-8B90-322E87B61853--
.
Author: Adi Shavit <adishavit@gmail.com>
Date: Sun, 31 Aug 2014 11:21:01 -0700 (PDT)
Raw View
------=_Part_104_1249219756.1409509261704
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hi David,
=20
> The difference between type-erased shared_ptr and fully-static unique_ptr=
,=20
> and its cousin scoped_resource, is an indirect function call. This is=20
> necessary because a shared_ptr can almost never expect to know the=20
> dynamic type of the object it retains, but most unique_ptr use cases=20
> statically know the dynamic type.
>
Hmmm.. I would think that with shared_ptr with a polymorphic class (where=
=20
you do not know the dynamic type), you would actually rely on the virtual=
=20
dtor in these cases and would most often stay with the default delete(er).=
=20
When trying to wrap C APIs your data would usually not be polymorphic e.g.=
=20
opaque values *or* pointers.
So it might seems that it is *these* cases where deleter type erasure may=
=20
be more useful.
For example, OpenGL has many components that are all referenced via simple=
=20
int IDs.
It is up-to the programmer to keep track of which int ID is which and how=
=20
each (resource ) should be released.=20
=20
> The solution is to add your own indirect call into the deleter, such as b=
y=20
> using a naked function pointer pointer type as the deleter, or by virtual=
=20
> operator ().
>
How would I do that if my deleter is actually a lambda?
It is often the case that a resource release function expects a ref to the=
=20
handle, so I would need to wrap it in some lamba.
If I have to write a class with a custom dtor for each of my resource kinds=
=20
(not necessarily different types), then this whole discussion is moot as it=
=20
means this class is not generic enough to let me apply RAII to any (simple)=
=20
resource.
=20
> For what it=E2=80=99s worth, I=E2=80=99m not convinced that scoped_resour=
ce provides any=20
> useful encapsulation. Simply writing a class with a destructor is more=20
> terse and more expository.
>
When using a 3rd-party C-API (e.g. OpenGL) I often don't want to write a=
=20
(yet-another) full blown wrapper library. I just want better resource=20
management.
It is always recommended that you handle your resource release at the point=
=20
of creation (that is the essence of RAII) - and a resource wrapper should=
=20
allow me to do this.
If I add/remove resources to/from the code, I do not need to keep track of=
=20
initialization and release at different points/methods.=20
=20
> Virtual destructors are among the most widely-known idioms in existence,=
=20
> and simply =E2=80=9Cdoing things the old-fashioned way=E2=80=9D would lik=
ely have avoided=20
> this deleter confusion entirely.
>
I am not sure I understand how this applies to our discussion.
Thank you,
Adi
--=20
---=20
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 e=
mail 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-proposa=
ls/.
------=_Part_104_1249219756.1409509261704
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hi David,</div><div> </div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;"><div style=3D"word-wrap:break-word"><div><div>The d=
ifference between type-erased <font face=3D"Courier">shared_ptr</font> and =
fully-static <font face=3D"Courier">unique_ptr</font>, and its cousin <font=
face=3D"Courier">scoped_resource</font>, is an indirect function call. Thi=
s is necessary because a <font face=3D"Courier">shared_ptr</font> can almos=
t never expect to know the dynamic type of the object it retains, but most&=
nbsp;<font face=3D"Courier">unique_ptr</font> use cases statically kno=
w the dynamic type.</div></div></div></blockquote><div><br></div><div>Hmmm.=
.. I would think that with <font face=3D"Courier">shared_ptr</font>&nbs=
p;with a polymorphic class (where you do not know the dynamic type), you wo=
uld actually rely on the virtual dtor in these cases and would most of=
ten stay with the default delete(er). When trying to wrap C APIs your data =
would usually not be polymorphic e.g. opaque values <i>or</i> pointers=
..</div><div>So it might seems that it is <i>these</i> cases where dele=
ter type erasure may be more useful.</div><div>For example, OpenGL has many=
components that are all referenced via simple int IDs.</div><div>It is up-=
to the programmer to keep track of which int ID is which and how each (reso=
urce ) should be released. </div><div> </div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;"><div style=3D"word-wrap:break-word"><div>The solut=
ion is to add your own indirect call into the deleter, such as by using a n=
aked function pointer pointer type as the deleter, or by <font face=3D"Cour=
ier">virtual operator ()</font>.<br></div></div></blockquote><div><br></div=
><div>How would I do that if my deleter is actually a lambda?</div><div>It =
is often the case that a resource release function expects a ref to the han=
dle, so I would need to wrap it in some lamba.</div><div><br></div><div>If =
I have to write a class with a custom dtor for each of my resource kinds (n=
ot necessarily different types), then this whole discussion is moot as it m=
eans this class is not generic enough to let me apply RAII to any (simple) =
resource.</div><div> </div><blockquote class=3D"gmail_quote" style=3D"=
margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;=
"><div style=3D"word-wrap:break-word"><div>For what it=E2=80=99s worth, I=
=E2=80=99m not convinced that <font face=3D"Courier">scoped_resource</font>=
provides any useful encapsulation. Simply writing a class with a destructo=
r is more terse and more expository.<br></div></div></blockquote><div><br><=
/div><div> When using a 3rd-party C-API (e.g. OpenGL) I often don't wa=
nt to write a (yet-another) full blown wrapper library. I just want better =
resource management.</div><div>It is always recommended that you handle you=
r resource release at the point of creation (that is the essence of RAII) -=
and a resource wrapper should allow me to do this.</div><div><br></div><di=
v>If I add/remove resources to/from the code, I do not need to keep track o=
f initialization and release at different points/methods. </div><div>&=
nbsp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-=
wrap:break-word"><div><div>Virtual destructors are among the most widely-kn=
own idioms in existence, and simply =E2=80=9Cdoing things the old-fashioned=
way=E2=80=9D would likely have avoided this deleter confusion entirely.</d=
iv></div></div></blockquote><div><br></div><div>I am not sure I understand =
how this applies to our discussion.</div><div><br></div><div>Thank you,</di=
v><div>Adi</div></div>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_104_1249219756.1409509261704--
.
Author: Andrew Sandoval <sandoval@netwaysglobal.com>
Date: Sun, 31 Aug 2014 12:21:44 -0700 (PDT)
Raw View
------=_Part_1_890328641.1409512904326
Content-Type: text/plain; charset=UTF-8
On Sunday, August 31, 2014 9:03:18 AM UTC-5, Adi Shavit wrote:
>
> Hi,
>
> It is often useful to have resources as members of a class to be cleaned
> upon destruction (this is what RAII is all about!).
> However, to declare a member of scoped_resource in the class header, I
> would need to know the type of the deleter (as opposed to, e.g. shared_ptr
> which does not require this).
> I guess I could use decltype in the member type definition, but that would
> require stating the actual deleter at 2 different places: header + the
> initialization.
>
> All the examples I saw use 'auto' for local scope, but AFAIK, you cannot
> use auto in the class declaration since the size needs to be known at
> compile time.
> Am I missing something here or is this by design?
> What is the rational for this and how would one a succinct scoped_resource
> declaration?
>
> Warm regards,
> Adi
>
Adi,
Unfortunately there is not a really good way to handle this with N3949.
The original proposal N3677 had a class called scoped_resource and examples
of how it could be used as a class member. And because the delete time
check was in the object's destructor instead of being a constructor
argument, the no-delete value wasn't checked until just before the delete
function would've been called (unlike N3949.)
Nevertheless, you can still do something similar. It's not great
syntactically, but here is an example:
#include "stdafx.h"
#include "N3949/unique_resource"
#include <windows.h>
#include <string>
class A
{
private:
std::experimental::unique_resource_t<HANDLE, decltype(&CloseHandle)>
m_hFile;
A() = delete;
public:
A(const std::wstring &wstrFile) :
m_hFile(CreateFile(wstrFile.c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr), &CloseHandle)
{
}
};
int main(int argc, const char* argv[])
{
A a(L"test.txt");
return 0;
}
As previously mentioned, the problem with the example is that you have to
really ugly it up to test the return value of CreateFile in order to pass a
true/false properly as the last parameter to unique_resource_t's
constructor. If we have auto class members then obviously it is much
easier and cleaner as you can use unique_resource to generate a
unique_resource_t.
Take a look at the examples in N3677 (
http://www.andrewlsandoval.com/scope_exit/) and N3830 (
http://www.andrewlsandoval.com/scoped_resource/N3830_scoped_resource.pdf)
for more history and details. Ultimately the Library Evolution Working
Group preferred the classes in N3949. Personally I would much rather have
N3949's classes in the standard library than not have anything! The "old
school" way that David mentioned may be different than what I have in mind,
but from my experience the old school way was to not use a class to
encapsulate, and that has resulted in a lot of code that leaks in general,
and even worse, leaks on unwind. (Worse because fewer developers are
cognizant of the risk of leaking on unwind.)
I strongly believe that by binding the clean-up to the initialization,
visibly and upfront, you cause the developer to think more carefully about
resource lifetime, resulting in better code. And, whether the old school
method is to create small objects that simply encapsulate and clean-up
(such as a File object with constructor opening a file, and the destructor
closing it), or if it is the manual C-style method, both tend to separate
and in some cases substantially distance initialization from clean-up and
therefore don't force the developer to think about resource lifetime up
front. And while it is obvious that this can work, it can also increase
the hard to catch bugs, especially in the latter case.
I hope that is helpful.
-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/.
------=_Part_1_890328641.1409512904326
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Sunday, August 31, 2014 9:03:18 AM UTC-5, Adi Shavit wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">Hi,<div><=
br></div><div> It is often useful to have resources as members of a c=
lass to be cleaned upon destruction (this is what RAII is all about!).</div=
><div>However, to declare a member of scoped_resource in the class header, =
I would need to know the type of the deleter (as opposed to, e.g. shared_pt=
r which does not require this).</div><div>I guess I could use decltype in t=
he member type definition, but that would require stating the actual delete=
r at 2 different places: header + the initialization.</div><div><br></div><=
div>All the examples I saw use 'auto' for local scope, but AFAIK, you canno=
t use auto in the class declaration since the size needs to be known at com=
pile time.</div><div>Am I missing something here or is this by design?</div=
><div>What is the rational for this and how would one a succinct scoped_res=
ource declaration?</div><div><br></div><div>Warm regards,</div><div>Adi</di=
v></div></blockquote><div><br>Adi,<br><br>Unfortunately there is not a real=
ly good way to handle this with N3949. The original proposal N3677 ha=
d a class called scoped_resource and examples of how it could be used as a =
class member. And because the delete time check was in the object's d=
estructor instead of being a constructor argument, the no-delete value wasn=
't checked until just before the delete function would've been called (unli=
ke N3949.)<br><br>Nevertheless, you can still do something similar. I=
t's not great syntactically, but here is an example:<br><br><div class=3D"p=
rettyprint" style=3D"background-color: rgb(250, 250, 250); border-color: rg=
b(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: break-=
word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span styl=
e=3D"color: #800;" class=3D"styled-by-prettify">#include</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #080;" class=3D"styled-by-prettify">"stdafx.h"</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #800=
;" class=3D"styled-by-prettify">#include</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=3D=
"styled-by-prettify">"N3949/unique_resource"</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #800;" c=
lass=3D"styled-by-prettify">#include</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=3D"sty=
led-by-prettify"><windows.h></span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #800;" class=3D"st=
yled-by-prettify">#include</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #080;" class=3D"styled-by-pre=
ttify"><string></span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br><br></span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">class</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> A<br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">private</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br> std</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">experimental</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">unique_resource_t</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">HANDLE</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">decltype</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(&</span><span style=3D"color: #606;" class=3D"=
styled-by-prettify">CloseHandle</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">)></span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> m_hFile</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br> A</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">()</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">delete</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color:=
#008;" class=3D"styled-by-prettify">public</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br> A</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">const</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">wstring </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">&</span><span style=3D"color: #000;" class=3D"styled-by-prettify">ws=
trFile</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> <br>  =
; m_hFile</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
</span><span style=3D"color: #606;" class=3D"styled-by-prettify">CreateFile=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">wstrFile</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">c_str</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">(),</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> GENERIC_READ</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> FILE_SHARE_READ</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">nullptr</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> OPEN_EXISTING</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
FILE_ATTRIBUTE_NORMAL</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">nullpt=
r</span><span style=3D"color: #660;" class=3D"styled-by-prettify">),</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">&</span><span style=3D=
"color: #606;" class=3D"styled-by-prettify">CloseHandle</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> main</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">int</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> arg=
c</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">const</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">char</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> argv</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">[])</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbs=
p; A a</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">L</spa=
n><span style=3D"color: #080;" class=3D"styled-by-prettify">"test.txt"</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br> </spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">return</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">0</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br><br></span></div></code></div><br><br>As previously ment=
ioned, the problem with the example is that you have to really ugly it up t=
o test the return value of CreateFile in order to pass a true/false properl=
y as the last parameter to unique_resource_t's constructor. If we hav=
e auto class members then obviously it is much easier and cleaner as you ca=
n use unique_resource to generate a unique_resource_t.<br><br>Take a look a=
t the examples in N3677 (<a href=3D"http://www.andrewlsandoval.com/scope_ex=
it/">http://www.andrewlsandoval.com/scope_exit/</a>) and N3830 (<a href=3D"=
http://www.andrewlsandoval.com/scoped_resource/N3830_scoped_resource.pdf">h=
ttp://www.andrewlsandoval.com/scoped_resource/N3830_scoped_resource.pdf</a>=
) for more history and details. Ultimately the Library Evolution Work=
ing Group preferred the classes in N3949. Personally I would much rat=
her have N3949's classes in the standard library than not have anything!&nb=
sp; The "old school" way that David mentioned may be different than what I =
have in mind, but from my experience the old school way was to not use a cl=
ass to encapsulate, and that has resulted in a lot of code that leaks in ge=
neral, and even worse, leaks on unwind. (Worse because fewer develope=
rs are cognizant of the risk of leaking on unwind.)<br><br>I strongly belie=
ve that by binding the clean-up to the initialization, visibly and upfront,=
you cause the developer to think more carefully about resource lifetime, r=
esulting in better code. And, whether the old school method is =
to create small objects that simply encapsulate and clean-up (such as a Fil=
e object with constructor opening a file, and the destructor closing it), o=
r if it is the manual C-style method, both tend to separate and in some cas=
es substantially distance initialization from clean-up and therefore don't =
force the developer to think about resource lifetime up front. And wh=
ile it is obvious that this can work, it can also increase the hard to catc=
h bugs, especially in the latter case.<br><br>I hope that is helpful.<br><b=
r>-Andrew Sandoval<br></div></div>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_1_890328641.1409512904326--
.
Author: David Krauss <potswa@gmail.com>
Date: Mon, 1 Sep 2014 08:19:27 +0800
Raw View
--Apple-Mail=_16AB018A-4F8E-4D70-B97D-3EDF0F926E84
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1
On 2014-09-01, at 2:21 AM, Adi Shavit <adishavit@gmail.com> wrote:
> For example, OpenGL has many components that are all referenced via simpl=
e int IDs.
> It is up-to the programmer to keep track of which int ID is which and how=
each (resource ) should be released.=20
An excellent job for a class. Define one class per type of resource.
> The solution is to add your own indirect call into the deleter, such as b=
y using a naked function pointer type as the deleter, or by virtual operato=
r ().
>=20
> How would I do that if my deleter is actually a lambda?
Captureless lambdas implicitly convert to a naked function pointer, and del=
eters are stateless/captureless, so use that alternative.
> It is often the case that a resource release function expects a ref to th=
e handle, so I would need to wrap it in some lamba.
You don't need a lambda; they have no special abilities that cannot be atta=
ined otherwise. They can capture local variables, but your use case, along =
with most use cases of scoped_resource, precludes captures being very usefu=
l.
> If I have to write a class with a custom dtor for each of my resource kin=
ds (not necessarily different types), then this whole discussion is moot as=
it means this class is not generic enough to let me apply RAII to any (sim=
ple) resource.
Use a polymorphic class.
> For what it's worth, I'm not convinced that scoped_resource provides any =
useful encapsulation. Simply writing a class with a destructor is more ters=
e and more expository.
>=20
> When using a 3rd-party C-API (e.g. OpenGL) I often don't want to write a=
(yet-another) full blown wrapper library. I just want better resource mana=
gement.
> It is always recommended that you handle your resource release at the poi=
nt of creation (that is the essence of RAII) - and a resource wrapper shoul=
d allow me to do this.
You can define a polymorphic class locally.
// header
struct opengl_resource {
GLuint id;
opengl_resource( GLuint in_id ) : id( in_id ) {}
virtual ~ opengl_resource() =3D 0;
};
inline opengl_resource::~ opengl_resource() =3D default;
typedef std::unique_ptr< opengl_resource > opengl_handle;
// implementation
void foo() {
struct shader : opengl_resource {
using opengl_resource::opengl_resource;
virtual ~ shader() {
glDeleteShader( id );
}
};
// Pass this handle out to any structure/function:
opengl_handle sh =3D std::make_unique< shader >( glCreateShader( GL_VER=
TEX_SHADER ) );
}
Over time, you can migrate the local classes into a wrapper library. There =
is no commitment to either keeping everything local precluding reusability =
nor to a "full-blown" library (although I don't see the risk in developing =
such a thin library as you go).
There is a little boilerplate, but it's totally obvious how everything work=
s. No room for error.
Destructors are (usually) implicitly noexcept, so using a non-noexcept func=
tion to define destructor functionality loses a little safety. The traditio=
nal way on the other hand is essentially perfect.
> Virtual destructors are among the most widely-known idioms in existence, =
and simply "doing things the old-fashioned way" would likely have avoided t=
his deleter confusion entirely.
>=20
> I am not sure I understand how this applies to our discussion.
Every workable solution deserves consideration. The apparent problem is mer=
ely that you believe classes should be declared in interface headers, but y=
ou want to have implementation classes. C++ has always supported implementa=
tion classes. Besides local classes, there are also unnamed namespaces. The=
re is no need to go back to the bad old days of function pointers.
--=20
---=20
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 e=
mail 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-proposa=
ls/.
--Apple-Mail=_16AB018A-4F8E-4D70-B97D-3EDF0F926E84
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=ISO-8859-1
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dwindows-1252"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-=
mode: space; -webkit-line-break: after-white-space;"><br><div><div>On 2014&=
ndash;09–01, at 2:21 AM, Adi Shavit <<a href=3D"mailto:adishavit@g=
mail.com">adishavit@gmail.com</a>> wrote:</div><br class=3D"Apple-interc=
hange-newline"><blockquote type=3D"cite"><div dir=3D"ltr"><div>For example,=
OpenGL has many components that are all referenced via simple int IDs.</di=
v><div>It is up-to the programmer to keep track of which int ID is which an=
d how each (resource ) should be released. </div></div></blockquote><d=
iv><br></div><div>An excellent job for a class. Define one class per type o=
f resource.</div><br><blockquote type=3D"cite"><div dir=3D"ltr"><blockquote=
class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-widt=
h: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; pa=
dding-left: 1ex; position: static; z-index: auto;"><div style=3D"word-wrap:=
break-word">The solution is to add your own indirect call into the deleter,=
such as by using a naked function pointer type as the deleter, or by <font=
face=3D"Courier">virtual operator ()</font>.<br></div></blockquote><div><b=
r></div><div>How would I do that if my deleter is actually a lambda?</div><=
/div></blockquote><div><br></div><div>Captureless lambdas implicitly conver=
t to a naked function pointer, and deleters are stateless/captureless, so u=
se that alternative.</div><br><blockquote type=3D"cite"><div dir=3D"ltr"><d=
iv>It is often the case that a resource release function expects a ref to t=
he handle, so I would need to wrap it in some lamba.</div></div></blockquot=
e><div><br></div><div>You don’t need a lambda; they have no special a=
bilities that cannot be attained otherwise. They can capture local variable=
s, but your use case, along with most use cases of <font face=3D"Courier">s=
coped_resource</font>, precludes captures being very useful.</div><br><bloc=
kquote type=3D"cite"><div dir=3D"ltr"><div>If I have to write a class with =
a custom dtor for each of my resource kinds (not necessarily different type=
s), then this whole discussion is moot as it means this class is not generi=
c enough to let me apply RAII to any (simple) resource.</div></div></blockq=
uote><div><br></div><div>Use a polymorphic class.</div><br><blockquote type=
=3D"cite"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margi=
n: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 2=
04, 204); border-left-style: solid; padding-left: 1ex; position: static; z-=
index: auto;"><div style=3D"word-wrap:break-word">For what it’s worth=
, I’m not convinced that <font face=3D"Courier">scoped_resource</font=
> provides any useful encapsulation. Simply writing a class with a destruct=
or is more terse and more expository.<br></div></blockquote><div><br></div>=
<div> When using a 3rd-party C-API (e.g. OpenGL) I often don't want to=
write a (yet-another) full blown wrapper library. I just want better resou=
rce management.</div><div>It is always recommended that you handle your res=
ource release at the point of creation (that is the essence of RAII) - and =
a resource wrapper should allow me to do this.</div></div></blockquote><div=
><br></div><div>You can define a polymorphic class locally.</div><div><br><=
/div><div><font face=3D"Courier">// header</font></div><div><font face=3D"C=
ourier">struct opengl_resource {</font></div><div><font face=3D"Courier">&n=
bsp; GLuint id;</font></div><div><font face=3D"Courier"><br></font><=
/div><div><font face=3D"Courier"> opengl_resource( GLuint in_i=
d ) : id( in_id ) {}</font></div><div><font face=3D"Courier"> =
virtual ~ opengl_resource() =3D 0;</font></div><div><font face=3D"Courier">=
};</font></div><div><font face=3D"Courier">inline opengl_resource::~ opengl=
_resource() =3D default;</font></div><div><font face=3D"Courier"><br></font=
></div><div><font face=3D"Courier">typedef </font><span style=3D"font-=
family: Courier;">std::unique_ptr< opengl_resource > opengl_handle;</=
span></div><div><font face=3D"Courier"><br></font></div><div><font face=3D"=
Courier">// implementation</font></div><div><font face=3D"Courier">void foo=
() {</font></div><div><font face=3D"Courier"> struct shader : =
opengl_resource {</font></div><div><font face=3D"Courier"> &nb=
sp; using opengl_resource::opengl_resource;</font></div><div><font f=
ace=3D"Courier"> virtual ~ </font><span sty=
le=3D"font-family: Courier;">shader</span><font face=3D"Courier">() {</font=
></div><div><font face=3D"Courier">  =
; glDeleteShader( id );</font></div><div><font face=3D"Courier"> =
}</font></div><div><font face=3D"Courier"> &nbs=
p; };</font></div><div><font face=3D"Courier"> // Pass this&nb=
sp;handle out to any structure/function:</font></div><div><font face=3D"Cou=
rier"> </font><span style=3D"font-family: Courier;">openg=
l_handle</span><font face=3D"Courier"> sh =3D std::make_unique< sha=
der >( glCreateShader( GL_VERTEX_SHADER ) );</font></div><div>=
<font face=3D"Courier">}</font></div><div><br></div><div>Over time, you can=
migrate the local classes into a wrapper library. There is no commitment t=
o either keeping everything local precluding reusability nor to a “fu=
ll-blown” library (although I don’t see the risk in developing =
such a thin library as you go).</div><div><br></div><div>There is a little =
boilerplate, but it’s totally obvious how everything works. No room f=
or error.</div><div><br></div><div>Destructors are (usually) implicitly noe=
xcept, so using a non-noexcept function to define destructor functionality =
loses a little safety. The traditional way on the other hand is essentially=
perfect.</div><br><blockquote type=3D"cite"><div dir=3D"ltr"><blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width:=
1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padd=
ing-left: 1ex; position: static; z-index: auto;"><div style=3D"word-wrap:br=
eak-word">Virtual destructors are among the most widely-known idioms in exi=
stence, and simply “doing things the old-fashioned way” would l=
ikely have avoided this deleter confusion entirely.</div></blockquote><div>=
<br></div><div>I am not sure I understand how this applies to our discussio=
n.</div></div></blockquote><br></div><div>Every workable solution deserves =
consideration. The apparent problem is merely that you believe classes shou=
ld be declared in interface headers, but you want to have implementation cl=
asses. C++ has always supported implementation classes. Besides local class=
es, there are also unnamed namespaces. There is no need to go back to the b=
ad old days of function pointers.</div><div><br></div></body></html>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_16AB018A-4F8E-4D70-B97D-3EDF0F926E84--
.
Author: Adi Shavit <adishavit@gmail.com>
Date: Mon, 1 Sep 2014 09:55:04 +0300
Raw View
--001a11c2ba8e5111670501fb7d9e
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hi David,
Thank you for the detailed explanation and the sample code.
Assuming we want/need to write new small classes, your approach, indeed,
reduces the amount of boilerplate and error-prone code and makes good use
of unique_ptr.
Ultimately, I think that it is a question of style, taste and context,
whether to write small (efficient) wrappers or try to use a generic wrapper
(which amounts to about one extra line of user code if at all). As you
mention, your suggestion is really an alternative to the classes proposed
in this proposal and is always a valid option regardless if this proposal
makes it into the standard or not.
I think that if your generalize and genericise the code in your example,
you will essentially get a version of scoped_resource sans virtual calls,
and possibly sans deleter type in type - which is basically what I wanted.
Since this discussion is in the context of the proposal itself (and more
generally, its applicability to common use cases), I think your suggestion
is important for understanding alternatives to common use cases and any
pros and cons each option has. It does not directly answer my original
question as to why the deleter type must be specified as part of the handle
type.
Warm regards,
Adi
On Mon, Sep 1, 2014 at 3:19 AM, David Krauss <potswa@gmail.com> wrote:
>
> On 2014=E2=80=9309=E2=80=9301, at 2:21 AM, Adi Shavit <adishavit@gmail.co=
m> wrote:
>
> For example, OpenGL has many components that are all referenced via simpl=
e
> int IDs.
> It is up-to the programmer to keep track of which int ID is which and how
> each (resource ) should be released.
>
>
> An excellent job for a class. Define one class per type of resource.
>
> The solution is to add your own indirect call into the deleter, such as b=
y
>> using a naked function pointer type as the deleter, or by virtual
>> operator ().
>>
>
> How would I do that if my deleter is actually a lambda?
>
>
> Captureless lambdas implicitly convert to a naked function pointer, and
> deleters are stateless/captureless, so use that alternative.
>
> It is often the case that a resource release function expects a ref to th=
e
> handle, so I would need to wrap it in some lamba.
>
>
> You don=E2=80=99t need a lambda; they have no special abilities that cann=
ot be
> attained otherwise. They can capture local variables, but your use case,
> along with most use cases of scoped_resource, precludes captures being
> very useful.
>
> If I have to write a class with a custom dtor for each of my resource
> kinds (not necessarily different types), then this whole discussion is mo=
ot
> as it means this class is not generic enough to let me apply RAII to any
> (simple) resource.
>
>
> Use a polymorphic class.
>
> For what it=E2=80=99s worth, I=E2=80=99m not convinced that scoped_resour=
ce provides any
>> useful encapsulation. Simply writing a class with a destructor is more
>> terse and more expository.
>>
>
> When using a 3rd-party C-API (e.g. OpenGL) I often don't want to write a
> (yet-another) full blown wrapper library. I just want better resource
> management.
> It is always recommended that you handle your resource release at the
> point of creation (that is the essence of RAII) - and a resource wrapper
> should allow me to do this.
>
>
> You can define a polymorphic class locally.
>
> // header
> struct opengl_resource {
> GLuint id;
>
> opengl_resource( GLuint in_id ) : id( in_id ) {}
> virtual ~ opengl_resource() =3D 0;
> };
> inline opengl_resource::~ opengl_resource() =3D default;
>
> typedef std::unique_ptr< opengl_resource > opengl_handle;
>
> // implementation
> void foo() {
> struct shader : opengl_resource {
> using opengl_resource::opengl_resource;
> virtual ~ shader() {
> glDeleteShader( id );
> }
> };
> // Pass this handle out to any structure/function:
> opengl_handle sh =3D std::make_unique< shader >( glCreateShader(
> GL_VERTEX_SHADER ) );
> }
>
> Over time, you can migrate the local classes into a wrapper library. Ther=
e
> is no commitment to either keeping everything local precluding reusabilit=
y
> nor to a =E2=80=9Cfull-blown=E2=80=9D library (although I don=E2=80=99t s=
ee the risk in developing
> such a thin library as you go).
>
> There is a little boilerplate, but it=E2=80=99s totally obvious how every=
thing
> works. No room for error.
>
> Destructors are (usually) implicitly noexcept, so using a non-noexcept
> function to define destructor functionality loses a little safety. The
> traditional way on the other hand is essentially perfect.
>
> Virtual destructors are among the most widely-known idioms in existence,
>> and simply =E2=80=9Cdoing things the old-fashioned way=E2=80=9D would li=
kely have avoided
>> this deleter confusion entirely.
>>
>
> I am not sure I understand how this applies to our discussion.
>
>
> Every workable solution deserves consideration. The apparent problem is
> merely that you believe classes should be declared in interface headers,
> but you want to have implementation classes. C++ has always supported
> implementation classes. Besides local classes, there are also unnamed
> namespaces. There is no need to go back to the bad old days of function
> pointers.
>
> --
>
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/GP8BVeW_LkI/=
unsubscribe
> .
> To unsubscribe from this group and all its topics, 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/.
>
--=20
---=20
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 e=
mail 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-proposa=
ls/.
--001a11c2ba8e5111670501fb7d9e
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Hi David,<div><br></div><div>=C2=A0 Thank you for the deta=
iled explanation and the sample code.</div><div>Assuming we want/need to wr=
ite new small classes, your approach, indeed, reduces the amount of boilerp=
late and error-prone code and makes good use of unique_ptr.</div>
<div><br></div><div>Ultimately, I think that it is a question of style, tas=
te and context, whether to write small (efficient) wrappers or try to use a=
generic wrapper (which amounts to about one extra line of user code if at =
all). As you mention, your suggestion is really an alternative to the class=
es proposed in this proposal and is always a valid option regardless if thi=
s proposal makes it into the standard or not.</div>
<div><br></div><div>I think that if your generalize and genericise the code=
in your example, you will essentially get a version of scoped_resource san=
s virtual calls, and possibly sans deleter type in type - which is basicall=
y what I wanted.=C2=A0</div>
<div><br></div><div>Since this discussion is in the context of the proposal=
itself (and more generally, its applicability to common use cases), I thin=
k your suggestion is important for understanding alternatives to common use=
cases and any pros and cons each option has. It does not directly answer m=
y original question as to why the deleter type must be specified as part of=
the handle type.</div>
<div><br></div><div>Warm regards,</div><div>Adi=C2=A0</div><div class=3D"gm=
ail_extra"><br><br><div class=3D"gmail_quote">On Mon, Sep 1, 2014 at 3:19 A=
M, David Krauss <span dir=3D"ltr"><<a href=3D"mailto:potswa@gmail.com" t=
arget=3D"_blank">potswa@gmail.com</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p=
adding-left:1ex"><div style=3D"word-wrap:break-word"><br><div><div class=3D=
"">
<div>
On 2014=E2=80=9309=E2=80=9301, at 2:21 AM, Adi Shavit <<a href=3D"mailto=
:adishavit@gmail.com" target=3D"_blank">adishavit@gmail.com</a>> wrote:<=
/div><br><blockquote type=3D"cite"><div dir=3D"ltr"><div>For example, OpenG=
L has many components that are all referenced via simple int IDs.</div>
<div>It is up-to the programmer to keep track of which int ID is which and =
how each (resource ) should be released.=C2=A0</div></div></blockquote><div=
><br></div></div><div>An excellent job for a class. Define one class per ty=
pe of resource.</div>
<br><blockquote type=3D"cite"><div dir=3D"ltr"><blockquote class=3D"gmail_q=
uote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-c=
olor:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style=
=3D"word-wrap:break-word">
The solution is to add your own indirect call into the deleter, such as by =
using a naked function pointer type as the deleter, or by <font face=3D"Cou=
rier">virtual operator ()</font>.<br></div></blockquote><div class=3D""><di=
v>
<br></div><div>How would I do that if my deleter is actually a lambda?</div=
></div></div></blockquote><div><br></div><div>Captureless lambdas implicitl=
y convert to a naked function pointer, and deleters are stateless/capturele=
ss, so use that alternative.</div>
<div class=3D""><br><blockquote type=3D"cite"><div dir=3D"ltr"><div>It is o=
ften the case that a resource release function expects a ref to the handle,=
so I would need to wrap it in some lamba.</div></div></blockquote><div><br=
>
</div>
</div><div>You don=E2=80=99t need a lambda; they have no special abilities =
that cannot be attained otherwise. They can capture local variables, but yo=
ur use case, along with most use cases of <font face=3D"Courier">scoped_res=
ource</font>, precludes captures being very useful.</div>
<div class=3D""><br><blockquote type=3D"cite"><div dir=3D"ltr"><div>If I ha=
ve to write a class with a custom dtor for each of my resource kinds (not n=
ecessarily different types), then this whole discussion is moot as it means=
this class is not generic enough to let me apply RAII to any (simple) reso=
urce.</div>
</div></blockquote><div><br></div></div><div>Use a polymorphic class.</div>=
<div class=3D""><br><blockquote type=3D"cite"><div dir=3D"ltr"><blockquote =
class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1=
px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:=
1ex">
<div style=3D"word-wrap:break-word">For what it=E2=80=99s worth, I=E2=80=99=
m not convinced that <font face=3D"Courier">scoped_resource</font> provides=
any useful encapsulation. Simply writing a class with a destructor is more=
terse and more expository.<br>
</div></blockquote><div><br></div><div>=C2=A0When using a 3rd-party C-API (=
e.g. OpenGL) I often don't want to write a (yet-another) full blown wra=
pper library. I just want better resource management.</div><div>It is alway=
s recommended that you handle your resource release at the point of creatio=
n (that is the essence of RAII) - and a resource wrapper should allow me to=
do this.</div>
</div></blockquote><div><br></div></div><div>You can define a polymorphic c=
lass locally.</div><div><br></div><div><font face=3D"Courier">// header</fo=
nt></div><div><font face=3D"Courier">struct opengl_resource {</font></div>
<div>
<font face=3D"Courier">=C2=A0 =C2=A0 GLuint id;</font></div><div><font face=
=3D"Courier"><br></font></div><div><font face=3D"Courier">=C2=A0 =C2=A0 ope=
ngl_resource( GLuint in_id ) : id( in_id ) {}</font></div><div><font face=
=3D"Courier">=C2=A0 =C2=A0 virtual ~ opengl_resource() =3D 0;</font></div>
<div><font face=3D"Courier">};</font></div><div><font face=3D"Courier">inli=
ne opengl_resource::~ opengl_resource() =3D default;</font></div><div><font=
face=3D"Courier"><br></font></div><div><font face=3D"Courier">typedef=C2=
=A0</font><span style=3D"font-family:Courier">std::unique_ptr< opengl_re=
source > opengl_handle;</span></div>
<div><font face=3D"Courier"><br></font></div><div><font face=3D"Courier">//=
implementation</font></div><div><font face=3D"Courier">void foo() {</font>=
</div><div><font face=3D"Courier">=C2=A0 =C2=A0 struct shader : opengl_reso=
urce {</font></div>
<div><font face=3D"Courier">=C2=A0 =C2=A0 =C2=A0 =C2=A0 using opengl_resour=
ce::opengl_resource;</font></div><div><font face=3D"Courier">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 virtual ~=C2=A0</font><span style=3D"font-family:Courier">sha=
der</span><font face=3D"Courier">() {</font></div>
<div><font face=3D"Courier">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0=
glDeleteShader( id );</font></div><div><font face=3D"Courier">=C2=A0 =C2=A0=
=C2=A0 =C2=A0 }</font></div><div><font face=3D"Courier">=C2=A0 =C2=A0 };</=
font></div><div><font face=3D"Courier">=C2=A0 =C2=A0 // Pass this=C2=A0hand=
le out to any structure/function:</font></div>
<div><font face=3D"Courier">=C2=A0 =C2=A0=C2=A0</font><span style=3D"font-f=
amily:Courier">opengl_handle</span><font face=3D"Courier">=C2=A0sh =3D std:=
:make_unique< shader >(=C2=A0glCreateShader( GL_VERTEX_SHADER )=C2=A0=
);</font></div><div><font face=3D"Courier">}</font></div>
<div><br></div><div>Over time, you can migrate the local classes into a wra=
pper library. There is no commitment to either keeping everything local pre=
cluding reusability nor to a =E2=80=9Cfull-blown=E2=80=9D library (although=
I don=E2=80=99t see the risk in developing such a thin library as you go).=
</div>
<div><br></div><div>There is a little boilerplate, but it=E2=80=99s totally=
obvious how everything works. No room for error.</div><div><br></div><div>=
Destructors are (usually) implicitly noexcept, so using a non-noexcept func=
tion to define destructor functionality loses a little safety. The traditio=
nal way on the other hand is essentially perfect.</div>
<div class=3D""><br><blockquote type=3D"cite"><div dir=3D"ltr"><blockquote =
class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1=
px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:=
1ex">
<div style=3D"word-wrap:break-word">
Virtual destructors are among the most widely-known idioms in existence, an=
d simply =E2=80=9Cdoing things the old-fashioned way=E2=80=9D would likely =
have avoided this deleter confusion entirely.</div></blockquote><div><br></=
div><div>I am not sure I understand how this applies to our discussion.</di=
v>
</div></blockquote><br></div></div><div>Every workable solution deserves co=
nsideration. The apparent problem is merely that you believe classes should=
be declared in interface headers, but you want to have implementation clas=
ses. C++ has always supported implementation classes. Besides local classes=
, there are also unnamed namespaces. There is no need to go back to the bad=
old days of function pointers.</div>
<div><br></div></div><div class=3D""><div class=3D"h5">
<p></p>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/GP8BVeW_LkI/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/isocpp.org/d/topic/std-proposals/GP8BVeW_LkI=
/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</div></div></blockquote></div><br></div></div>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--001a11c2ba8e5111670501fb7d9e--
.