Topic: std::make_shared and std::allocate_shared --
Author: =?UTF-8?Q?David_Rodr=C3=ADguez_Ibeas?= <dibeas@ieee.org>
Date: Fri, 16 Jan 2015 15:53:48 -0500
Raw View
--089e01494c2a56a78d050ccb2ba2
Content-Type: text/plain; charset=UTF-8
Currently, 'make_shared' and 'allocate_shared' will execute the constructor
of the object over a chunk of memory allocated together with the reference
count object. The standard does not place any restrictions on how this is
done and the actual code doing the construction is often an implementation
detail of the library in use.
In some cases I have encountered the need (well, probably "want" with
enough time I would have refactored) to use
'std::enable_shared_from_this<T>' and in those cases management of the
object through a 'shared_ptr' was a requirement (i.e. the object could not
function correctly unless managed by 'shared_ptr' and 'shared_from_this()'
returning a valid 'shared_ptr').
To enforce that invariant in the type system the obvious approach is to
make the constructor private, and have a static factory function that
returns the 'shared_ptr'. This requires separate allocation of the object
and the reference count, since the constructor being private means that
'make_shared' cannot execute it, leading to implementations that don't
collocate the reference count in the one use case where it is clear that
the object will be managed by shared pointer.
The solution I have used in the past for this is to make the constructor
public, but provide an private 'ConstructorKey' type:
class T : std::enable_shared_from_this<T> {
class Key {};
public:
T(Key);
static std::shared_ptr<T> create() { return std::make_shared<T>(Key());
}
};
The constructor is syntactically 'public', but without accesss to 'Key' no
code outside of 'T' can create objects.
While this works, it seems a bit of a hack and depending on the ABI it has
(small) runtime cost. For example, the Itanium ABI requires that a register
is allocated for passing the 'Key' object to the constructor. [Note:
performance is not the motivation for this, the effect of flushing one
register is negligible in the grand scheme of a dynamic allocation and
object construction!]
It would not be hard to specify how the object is really constructed, so
that the class can enable the use of 'make_shared'/'allocate_shared'. Since
the use case in mind is for types that use the 'enable_shared_from_this'
base, I initially thought of requiring the following static member function
in that type:
template <typename T>
template <typename ... Args>
void enable_shared_from_this<T>::construct(void *p, Args ... args) {
new (p) T(std::forwrad<Args>(args)...);
}
And require that construction inside 'make_shared' and 'allocate_shared'
use that function to create the object. Then user code could use
friendship to grant access to these utility functions without affecting the
runtime:
class T : std::enable_shared_from_this<T> {
friend class enable_shared_from_this<T>; // or even:
friend void enable_shared_from_this<T>::construct<void>;
T();
public:
std::shared_ptr<T> create() {
return std::make_shared<T>();
}
};
I don't have any special interest in that function being inside
'std::enable_shared_from_this', it could be inside 'shared_ptr', or even as
an utility function called from 'make_shared'/'allocate_shared'.
Any thoughts?
David
--
---
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/.
--089e01494c2a56a78d050ccb2ba2
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Currently, 'make_shared' and 'allocate_shared&=
#39; will execute the constructor of the object over a chunk of memory allo=
cated together with the reference count object.=C2=A0 The standard does not=
place any restrictions on how this is done and the actual code doing the c=
onstruction is often an implementation detail of the library in use.<br><br=
>In some cases I have encountered the need (well, probably "want"=
with enough time I would have refactored) to use 'std::enable_shared_f=
rom_this<T>' and in those cases management of the object through =
a 'shared_ptr' was a requirement (i.e. the object could not functio=
n correctly unless managed by 'shared_ptr' and 'shared_from_thi=
s()' returning a valid 'shared_ptr').<br><br>To enforce that in=
variant in the type system the obvious approach is to make the constructor =
private, and have a static factory function that returns the 'shared_pt=
r'. This requires separate allocation of the object and the reference c=
ount, since the constructor being private means that 'make_shared' =
cannot execute it, leading to implementations that don't collocate the =
reference count in the one use case where it is clear that the object will =
be managed by shared pointer.<br><br>The solution I have used in the past f=
or this is to make the constructor public, but provide an private 'Cons=
tructorKey' type:<br><br>class T : std::enable_shared_from_this<T>=
; {<br>=C2=A0 =C2=A0 class Key {};<br>=C2=A0 public:<br>=C2=A0 =C2=A0 T(Key=
);<br>=C2=A0 =C2=A0 static std::shared_ptr<T> create() { return std::=
make_shared<T>(Key()); }<br>};<br><br>The constructor is syntacticall=
y 'public', but without accesss to 'Key' no code outside of=
'T' can create objects.<br><br>While this works, it seems a bit of=
a hack and depending on the ABI it has (small) runtime cost. For example, =
the Itanium ABI requires that a register is allocated for passing the '=
Key' object to the constructor. [Note: performance is not the motivatio=
n for this, the effect of flushing one register is negligible in the grand =
scheme of a dynamic allocation and object construction!]<br><br>It would no=
t be hard to specify how the object is really constructed, so that the clas=
s can enable the use of 'make_shared'/'allocate_shared'. Si=
nce the use case in mind is for types that use the 'enable_shared_from_=
this' base, I initially thought of requiring the following static membe=
r function in that type:<br><br>template <typename T><br>template <=
;typename ... Args><br>void enable_shared_from_this<T>::construct(=
void *p, Args ... args) {<br>=C2=A0 =C2=A0 new (p) T(std::forwrad<Args&g=
t;(args)...);<br>}<br><br>And require that construction inside 'make_sh=
ared' and 'allocate_shared' use that function to create the obj=
ect.=C2=A0 Then user code could use friendship to grant access to these uti=
lity functions without affecting the runtime:<br><br>class T : std::enable_=
shared_from_this<T> {<br>=C2=A0 =C2=A0 friend class enable_shared_fro=
m_this<T>; // or even:<br>=C2=A0 =C2=A0 friend void enable_shared_fro=
m_this<T>::construct<void>;<br>=C2=A0 =C2=A0 T();<br>=C2=A0 pub=
lic:<br>=C2=A0 =C2=A0 =C2=A0std::shared_ptr<T> create() {<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0return std::make_shared<T>();<br>=C2=A0 =
=C2=A0 =C2=A0}<br>};<br><br>I don't have any special interest in that f=
unction being inside 'std::enable_shared_from_this', it could be in=
side 'shared_ptr', or even as an utility function called from '=
make_shared'/'allocate_shared'.<br><br>Any thoughts?<br><br>=C2=
=A0 =C2=A0 David</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 />
--089e01494c2a56a78d050ccb2ba2--
.
Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Fri, 16 Jan 2015 15:18:55 -0800 (PST)
Raw View
------=_Part_999_99328060.1421450335745
Content-Type: multipart/alternative;
boundary="----=_Part_1000_811910701.1421450335745"
------=_Part_1000_811910701.1421450335745
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Friday, January 16, 2015 at 12:53:50 PM UTC-8, David Rodr=C3=ADguez Ibea=
s=20
wrote:
>
>
> To enforce that invariant in the type system the obvious approach is to=
=20
> make the constructor private, and have a static factory function that=20
> returns the 'shared_ptr'. This requires separate allocation of the object=
=20
> and the reference count, since the constructor being private means that=
=20
> 'make_shared' cannot execute it, leading to implementations that don't=20
> collocate the reference count in the one use case where it is clear that=
=20
> the object will be managed by shared pointer.
>
Isn't this sufficiently solved by making std::make_shared a `friend` of=20
your class?
If `friend`ing make_shared is possible, what does the code look like in=20
that case?
=E2=80=93Arthur
>
--=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_1000_811910701.1421450335745
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Friday, January 16, 2015 at 12:53:50 PM UTC-8, David Ro=
dr=C3=ADguez Ibeas wrote:<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"><br>To enforce that invariant in the type system the obvious ap=
proach is to make the constructor private, and have a static factory functi=
on that returns the 'shared_ptr'. This requires separate allocation of the =
object and the reference count, since the constructor being private means t=
hat 'make_shared' cannot execute it, leading to implementations that don't =
collocate the reference count in the one use case where it is clear that th=
e object will be managed by shared pointer.<br></div></blockquote><div><br>=
</div><div>Isn't this sufficiently solved by making std::make_shared a `fri=
end` of your class?</div><div>If `friend`ing make_shared is possible, what =
does the code look like in that case?</div><div><br></div><div>=E2=80=93Art=
hur</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
</blockquote></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_1000_811910701.1421450335745--
------=_Part_999_99328060.1421450335745--
.
Author: Nevin Liber <nevin@eviloverlord.com>
Date: Fri, 16 Jan 2015 18:05:12 -0600
Raw View
--001a11c1a24246b887050ccdda21
Content-Type: text/plain; charset=UTF-8
On 16 January 2015 at 17:18, Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
wrote:
> Isn't this sufficiently solved by making std::make_shared a `friend` of
> your class?
>
No, because make_shared may delegate the construction to another object,
such as an allocator.
--
Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404
--
---
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/.
--001a11c1a24246b887050ccdda21
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><br><div class=3D"gmail_quote">=
On 16 January 2015 at 17:18, Arthur O'Dwyer <span dir=3D"ltr"><<a hr=
ef=3D"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@g=
mail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Isn=
't this sufficiently solved by making std::make_shared a `friend` of yo=
ur class?</div></blockquote><div><br></div><div>No, because make_shared may=
delegate the construction to another object, such as an allocator.</div></=
div>-- <br><div class=3D"gmail_signature">=C2=A0Nevin ":-)" Liber=
=C2=A0 <mailto:<a href=3D"mailto:nevin@eviloverlord.com" target=3D"_blan=
k">nevin@eviloverlord.com</a>>=C2=A0 (847) 691-1404</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 />
--001a11c1a24246b887050ccdda21--
.
Author: Jared Grubb <jared.grubb@gmail.com>
Date: Fri, 16 Jan 2015 23:41:56 -0800 (PST)
Raw View
------=_Part_403_902595985.1421480516681
Content-Type: multipart/alternative;
boundary="----=_Part_404_106237487.1421480516681"
------=_Part_404_106237487.1421480516681
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Big +1 from me. I have struggled with this problem as well. I think doing=
=20
"friend shared_from_this" is a simple and reasonable solution.
Jared
On Friday, January 16, 2015 at 12:53:50 PM UTC-8, David Rodr=C3=ADguez Ibea=
s=20
wrote:
>
> Currently, 'make_shared' and 'allocate_shared' will execute the=20
> constructor of the object over a chunk of memory allocated together with=
=20
> the reference count object. The standard does not place any restrictions=
=20
> on how this is done and the actual code doing the construction is often a=
n=20
> implementation detail of the library in use.
>
> In some cases I have encountered the need (well, probably "want" with=20
> enough time I would have refactored) to use=20
> 'std::enable_shared_from_this<T>' and in those cases management of the=20
> object through a 'shared_ptr' was a requirement (i.e. the object could no=
t=20
> function correctly unless managed by 'shared_ptr' and 'shared_from_this()=
'=20
> returning a valid 'shared_ptr').
>
> To enforce that invariant in the type system the obvious approach is to=
=20
> make the constructor private, and have a static factory function that=20
> returns the 'shared_ptr'. This requires separate allocation of the object=
=20
> and the reference count, since the constructor being private means that=
=20
> 'make_shared' cannot execute it, leading to implementations that don't=20
> collocate the reference count in the one use case where it is clear that=
=20
> the object will be managed by shared pointer.
>
> The solution I have used in the past for this is to make the constructor=
=20
> public, but provide an private 'ConstructorKey' type:
>
> class T : std::enable_shared_from_this<T> {
> class Key {};
> public:
> T(Key);
> static std::shared_ptr<T> create() { return=20
> std::make_shared<T>(Key()); }
> };
>
> The constructor is syntactically 'public', but without accesss to 'Key' n=
o=20
> code outside of 'T' can create objects.
>
> While this works, it seems a bit of a hack and depending on the ABI it ha=
s=20
> (small) runtime cost. For example, the Itanium ABI requires that a regist=
er=20
> is allocated for passing the 'Key' object to the constructor. [Note:=20
> performance is not the motivation for this, the effect of flushing one=20
> register is negligible in the grand scheme of a dynamic allocation and=20
> object construction!]
>
> It would not be hard to specify how the object is really constructed, so=
=20
> that the class can enable the use of 'make_shared'/'allocate_shared'. Sin=
ce=20
> the use case in mind is for types that use the 'enable_shared_from_this'=
=20
> base, I initially thought of requiring the following static member functi=
on=20
> in that type:
>
> template <typename T>
> template <typename ... Args>
> void enable_shared_from_this<T>::construct(void *p, Args ... args) {
> new (p) T(std::forwrad<Args>(args)...);
> }
>
> And require that construction inside 'make_shared' and 'allocate_shared'=
=20
> use that function to create the object. Then user code could use=20
> friendship to grant access to these utility functions without affecting t=
he=20
> runtime:
>
> class T : std::enable_shared_from_this<T> {
> friend class enable_shared_from_this<T>; // or even:
> friend void enable_shared_from_this<T>::construct<void>;
> T();
> public:
> std::shared_ptr<T> create() {
> return std::make_shared<T>();
> }
> };
>
> I don't have any special interest in that function being inside=20
> 'std::enable_shared_from_this', it could be inside 'shared_ptr', or even =
as=20
> an utility function called from 'make_shared'/'allocate_shared'.
>
> Any thoughts?
>
> David
>
--=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_404_106237487.1421480516681
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Big +1 from me. I have struggled with this problem as well=
.. I think doing "friend shared_from_this" is a simple and reasonable soluti=
on.<br><br>Jared<br><br>On Friday, January 16, 2015 at 12:53:50 PM UTC-8, D=
avid Rodr=C3=ADguez Ibeas wrote:<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">Currently, 'make_shared' and 'allocate_shared' will exec=
ute the constructor of the object over a chunk of memory allocated together=
with the reference count object. The standard does not place any res=
trictions on how this is done and the actual code doing the construction is=
often an implementation detail of the library in use.<br><br>In some cases=
I have encountered the need (well, probably "want" with enough time I woul=
d have refactored) to use 'std::enable_shared_from_this<<wbr>T>' and =
in those cases management of the object through a 'shared_ptr' was a requir=
ement (i.e. the object could not function correctly unless managed by 'shar=
ed_ptr' and 'shared_from_this()' returning a valid 'shared_ptr').<br><br>To=
enforce that invariant in the type system the obvious approach is to make =
the constructor private, and have a static factory function that returns th=
e 'shared_ptr'. This requires separate allocation of the object and the ref=
erence count, since the constructor being private means that 'make_shared' =
cannot execute it, leading to implementations that don't collocate the refe=
rence count in the one use case where it is clear that the object will be m=
anaged by shared pointer.<br><br>The solution I have used in the past for t=
his is to make the constructor public, but provide an private 'ConstructorK=
ey' type:<br><br>class T : std::enable_shared_from_this<<wbr>T> {<br>=
class Key {};<br> public:<br> T(Key);<br>&=
nbsp; static std::shared_ptr<T> create() { return std::make_sh=
ared<T>(Key()); }<br>};<br><br>The constructor is syntactically 'publ=
ic', but without accesss to 'Key' no code outside of 'T' can create objects=
..<br><br>While this works, it seems a bit of a hack and depending on the AB=
I it has (small) runtime cost. For example, the Itanium ABI requires that a=
register is allocated for passing the 'Key' object to the constructor. [No=
te: performance is not the motivation for this, the effect of flushing one =
register is negligible in the grand scheme of a dynamic allocation and obje=
ct construction!]<br><br>It would not be hard to specify how the object is =
really constructed, so that the class can enable the use of 'make_shared'/'=
allocate_<wbr>shared'. Since the use case in mind is for types that use the=
'enable_shared_from_this' base, I initially thought of requiring the follo=
wing static member function in that type:<br><br>template <typename T>=
;<br>template <typename ... Args><br>void enable_shared_from_this<=
T>::<wbr>construct(void *p, Args ... args) {<br> new (p) T(=
std::forwrad<Args>(args)...)<wbr>;<br>}<br><br>And require that const=
ruction inside 'make_shared' and 'allocate_shared' use that function to cre=
ate the object. Then user code could use friendship to grant access t=
o these utility functions without affecting the runtime:<br><br>class T : s=
td::enable_shared_from_this<<wbr>T> {<br> friend class e=
nable_shared_from_this<T>; // or even:<br> friend void e=
nable_shared_from_this<T>::<wbr>construct<void>;<br> &nbs=
p; T();<br> public:<br> std::shared_ptr<T> c=
reate() {<br> return std::make_shared<T=
>();<br> }<br>};<br><br>I don't have any special inte=
rest in that function being inside 'std::enable_shared_from_this'<wbr>, it =
could be inside 'shared_ptr', or even as an utility function called from 'm=
ake_shared'/'allocate_<wbr>shared'.<br><br>Any thoughts?<br><br> &nbs=
p; David</div>
</blockquote></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_404_106237487.1421480516681--
------=_Part_403_902595985.1421480516681--
.
Author: =?UTF-8?Q?David_Rodr=C3=ADguez_Ibeas?= <dibeas@ieee.org>
Date: Tue, 20 Jan 2015 14:52:33 +0000
Raw View
--001a11351944d151e9050d169627
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Just to be clear, the proposal would be to specify the exact mechanism used
to create your object such that users have the option of calling it out
(and befriending it). Whether this is a member of
'enable_shared_from_this', or 'shared_ptr' or anything else is less
important than allowing users to befriend this "creator" function/type.
@Arthur: 'make_shared' is allowed to delegate to a different
function/mechanism the construction of the object. This is not theoretical,
as there are implementations that do this, which means that you cannot
write portable code with no overhead.
David
On Sat Jan 17 2015 at 2:41:57 AM Jared Grubb <jared.grubb@gmail.com> wrote:
> Big +1 from me. I have struggled with this problem as well. I think doing
> "friend shared_from_this" is a simple and reasonable solution.
>
>
> Jared
>
>
> On Friday, January 16, 2015 at 12:53:50 PM UTC-8, David Rodr=C3=ADguez Ib=
eas
> wrote:
>
>> Currently, 'make_shared' and 'allocate_shared' will execute the
>> constructor of the object over a chunk of memory allocated together with
>> the reference count object. The standard does not place any restriction=
s
>> on how this is done and the actual code doing the construction is often =
an
>> implementation detail of the library in use.
>>
>> In some cases I have encountered the need (well, probably "want" with
>> enough time I would have refactored) to use 'std::enable_shared_from_thi=
s<T>'
>> and in those cases management of the object through a 'shared_ptr' was a
>> requirement (i.e. the object could not function correctly unless managed=
by
>> 'shared_ptr' and 'shared_from_this()' returning a valid 'shared_ptr').
>>
>> To enforce that invariant in the type system the obvious approach is to
>> make the constructor private, and have a static factory function that
>> returns the 'shared_ptr'. This requires separate allocation of the objec=
t
>> and the reference count, since the constructor being private means that
>> 'make_shared' cannot execute it, leading to implementations that don't
>> collocate the reference count in the one use case where it is clear that
>> the object will be managed by shared pointer.
>>
>> The solution I have used in the past for this is to make the constructor
>> public, but provide an private 'ConstructorKey' type:
>>
>> class T : std::enable_shared_from_this<T> {
>> class Key {};
>> public:
>> T(Key);
>> static std::shared_ptr<T> create() { return
>> std::make_shared<T>(Key()); }
>> };
>>
>> The constructor is syntactically 'public', but without accesss to 'Key'
>> no code outside of 'T' can create objects.
>>
>> While this works, it seems a bit of a hack and depending on the ABI it
>> has (small) runtime cost. For example, the Itanium ABI requires that a
>> register is allocated for passing the 'Key' object to the constructor.
>> [Note: performance is not the motivation for this, the effect of flushin=
g
>> one register is negligible in the grand scheme of a dynamic allocation a=
nd
>> object construction!]
>>
>> It would not be hard to specify how the object is really constructed, so
>> that the class can enable the use of 'make_shared'/'allocate_shared'.
>> Since the use case in mind is for types that use the
>> 'enable_shared_from_this' base, I initially thought of requiring the
>> following static member function in that type:
>>
>> template <typename T>
>> template <typename ... Args>
>> void enable_shared_from_this<T>::construct(void *p, Args ... args) {
>> new (p) T(std::forwrad<Args>(args)...);
>> }
>>
>> And require that construction inside 'make_shared' and 'allocate_shared'
>> use that function to create the object. Then user code could use
>> friendship to grant access to these utility functions without affecting =
the
>> runtime:
>>
>> class T : std::enable_shared_from_this<T> {
>> friend class enable_shared_from_this<T>; // or even:
>> friend void enable_shared_from_this<T>::construct<void>;
>> T();
>> public:
>> std::shared_ptr<T> create() {
>> return std::make_shared<T>();
>> }
>> };
>>
>> I don't have any special interest in that function being inside
>> 'std::enable_shared_from_this', it could be inside 'shared_ptr', or even
>> as an utility function called from 'make_shared'/'allocate_shared'.
>>
>> Any thoughts?
>>
>> David
>>
> --
>
> ---
> 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/.
>
--=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/.
--001a11351944d151e9050d169627
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Just to be clear, the proposal would be to specify the exact mechanism used=
to create your object such that users have the option of calling it out (a=
nd befriending it).=C2=A0 Whether this is a member of 'enable_shared_fr=
om_this', or 'shared_ptr' or anything else is less important th=
an allowing users to befriend this "creator" function/type.<br><b=
r>@Arthur: 'make_shared' is allowed to delegate to a different func=
tion/mechanism the construction of the object. This is not theoretical, as =
there are implementations that do this, which means that you cannot write p=
ortable code with no overhead.<br><br>=C2=A0 =C2=A0 David<br><div class=3D"=
gmail_quote">On Sat Jan 17 2015 at 2:41:57 AM Jared Grubb <<a href=3D"ma=
ilto:jared.grubb@gmail.com">jared.grubb@gmail.com</a>> wrote:<br><blockq=
uote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc =
solid;padding-left:1ex"><div dir=3D"ltr">Big +1 from me. I have struggled w=
ith this problem as well. I think doing "friend shared_from_this"=
is a simple and reasonable solution.</div><div dir=3D"ltr"><br><br>Jared</=
div><div dir=3D"ltr"><br><br>On Friday, January 16, 2015 at 12:53:50 PM UTC=
-8, David Rodr=C3=ADguez Ibeas wrote:</div><div dir=3D"ltr"><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc=
solid;padding-left:1ex"><div dir=3D"ltr">Currently, 'make_shared' =
and 'allocate_shared' will execute the constructor of the object ov=
er a chunk of memory allocated together with the reference count object.=C2=
=A0 The standard does not place any restrictions on how this is done and th=
e actual code doing the construction is often an implementation detail of t=
he library in use.<br><br>In some cases I have encountered the need (well, =
probably "want" with enough time I would have refactored) to use =
'std::enable_shared_from_this<<u></u>T>' and in those cases m=
anagement of the object through a 'shared_ptr' was a requirement (i=
..e. the object could not function correctly unless managed by 'shared_p=
tr' and 'shared_from_this()' returning a valid 'shared_ptr&=
#39;).<br><br>To enforce that invariant in the type system the obvious appr=
oach is to make the constructor private, and have a static factory function=
that returns the 'shared_ptr'. This requires separate allocation o=
f the object and the reference count, since the constructor being private m=
eans that 'make_shared' cannot execute it, leading to implementatio=
ns that don't collocate the reference count in the one use case where i=
t is clear that the object will be managed by shared pointer.<br><br>The so=
lution I have used in the past for this is to make the constructor public, =
but provide an private 'ConstructorKey' type:<br><br>class T : std:=
:enable_shared_from_this<<u></u>T> {<br>=C2=A0 =C2=A0 class Key {};<b=
r>=C2=A0 public:<br>=C2=A0 =C2=A0 T(Key);<br>=C2=A0 =C2=A0 static std::shar=
ed_ptr<T> create() { return std::make_shared<T>(Key()); }<br>};=
<br><br>The constructor is syntactically 'public', but without acce=
sss to 'Key' no code outside of 'T' can create objects.<br>=
<br>While this works, it seems a bit of a hack and depending on the ABI it =
has (small) runtime cost. For example, the Itanium ABI requires that a regi=
ster is allocated for passing the 'Key' object to the constructor. =
[Note: performance is not the motivation for this, the effect of flushing o=
ne register is negligible in the grand scheme of a dynamic allocation and o=
bject construction!]<br><br>It would not be hard to specify how the object =
is really constructed, so that the class can enable the use of 'make_sh=
ared'/'allocate_<u></u>shared'. Since the use case in mind is f=
or types that use the 'enable_shared_from_this' base, I initially t=
hought of requiring the following static member function in that type:<br><=
br>template <typename T><br>template <typename ... Args><br>voi=
d enable_shared_from_this<T>::<u></u>construct(void *p, Args ... args=
) {<br>=C2=A0 =C2=A0 new (p) T(std::forwrad<Args>(args)...)<u></u>;<b=
r>}<br><br>And require that construction inside 'make_shared' and &=
#39;allocate_shared' use that function to create the object.=C2=A0 Then=
user code could use friendship to grant access to these utility functions =
without affecting the runtime:<br><br>class T : std::enable_shared_from_thi=
s<<u></u>T> {<br>=C2=A0 =C2=A0 friend class enable_shared_from_this&l=
t;T>; // or even:<br>=C2=A0 =C2=A0 friend void enable_shared_from_this&l=
t;T>::<u></u>construct<void>;<br>=C2=A0 =C2=A0 T();<br>=C2=A0 publ=
ic:<br>=C2=A0 =C2=A0 =C2=A0std::shared_ptr<T> create() {<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0return std::make_shared<T>();<br>=C2=A0 =
=C2=A0 =C2=A0}<br>};<br><br>I don't have any special interest in that f=
unction being inside 'std::enable_shared_from_this'<u></u>, it coul=
d be inside 'shared_ptr', or even as an utility function called fro=
m 'make_shared'/'allocate_<u></u>shared'.<br><br>Any though=
ts?<br><br>=C2=A0 =C2=A0 David</div>
</blockquote></div><div dir=3D"ltr"></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" target=3D"_=
blank">std-proposals+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>
</blockquote></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 />
--001a11351944d151e9050d169627--
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Tue, 20 Jan 2015 13:08:15 -0800
Raw View
On Tue, Jan 20, 2015 at 6:52 AM, David Rodr=C3=ADguez Ibeas <dibeas@ieee.or=
g> wrote:
> Just to be clear, the proposal would be to specify the exact mechanism us=
ed
> to create your object such that users have the option of calling it out (=
and
> befriending it). Whether this is a member of 'enable_shared_from_this', =
or
> 'shared_ptr' or anything else is less important than allowing users to
> befriend this "creator" function/type.
Just for the sake of argument...
An alternative, MUCH more ambitious, solution would be to propose a
mechanism by which friendship can be transferred from one class to
another. I.e., right now we have
(A grants friendship to B) implies (B can touch A's private members)
(B grants friendship to C) implies (C can touch B's private members)
but we don't have
(A grants friendship to B) && (B grants some new kind of
super-friendship to C) implies (C can touch A's private members)
If we had such a mechanism, make_shared could grant super-friendship
to whatever entity is in charge of the allocation.
(This is almost certainly a terrible idea.)
If a proposal comes out of the OP (as I think one should), it should
mention this alternative, even if only to demolish it. :)
> @Arthur: 'make_shared' is allowed to delegate to a different
> function/mechanism the construction of the object. This is not theoretica=
l,
> as there are implementations that do this, which means that you cannot wr=
ite
> portable code with no overhead.
Yes, I get it now. Thanks for the clarification; I agree that this
feature would be very nice to have.
=E2=80=93Arthur
--=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/.
.