Topic: Feedback on N4025 (Exploring classes of runtime size)
Author: Giovanni Piero Deretta <gpderetta@gmail.com>
Date: Mon, 2 Jun 2014 09:06:23 -0700 (PDT)
Raw View
------=_Part_363_32856272.1401725183828
Content-Type: text/plain; charset=UTF-8
Hi all,
As per title, I have some feedback on N4025.
For those who haven't read it yet, this paper allows for runtime sized
array members of structs; critically, it differentiates from other
proposals by not requiring the constructor to be inline. If I
understand correctly, space allocation is done by providing a two
phase construction process for a class. At runtime a compiler
generated function, keyed on the constructor function, is
transparently called by the runtime to compute the (stack or heap)
allocation size. From the paper it is not clear how runtime sized
objects are returned or if they are allowed to be returned at all.
I'm not really sold on the syntax, in particular I think that the
runtime evaluated sizeof() might not fly with the many in the
committee, but I'll leave the bike-shedding to others. I do like the
semantics in general and I would hope that it gets in the standard in
some form.
My use case is not really run time sized arrays, but an alternative to
compiler firewalls.
As most C++ programmers know, on large codebases, is often desirable
to hide the implementation details of a class from its header file,
especially if the implementation details change often, to minimise the
amount of translation units that need recompilation when an
implementation changes; similarly implementation hiding also allows
for more robust ABIs.
The way that hiding is currently implemented is either via published
base classes that define virtual functions implemented by unpublished
derived classes and then delegating construction to factories, or via
the well known pimple idiom (a.k.a. letter/envelope): the actual
implementation is delegated to a private class which is not exposed to
client code, the published class only has a pointer to the
implementation class and forwards all its functionality to it.
Both idioms have drawbacks, base classes and virtual functions pretty
much require heap allocation, and virtual dispatch adds some overhead,
while the pimple idiom, in addition to the extra indirection (which
also requires heap allocation), requires writing a lot of boilerplate
code that does the forwarding.
A third solution is to do away with the interface/implementation and
have the class contain only a single array of chars, sized big enough
to contain the actual implementation plus additional space:
// MyClass.h
struct MyClass {
MyClass();
void Frob();
private:
struct MyClassImpl;
MyClassImpl& impl();
alignas(long) char buf[1024];
};
//MyClass.cpp:
MyClass::MyClassImpl {
long myFieldA;
long myFieldB;
int myFieldC; ...
};
MyClass::MyClass() {
static_assert(sizeof(MyClassImpl) <= sizeof(buf));
static_assert(alignof(MyClassImpl) <= alignof(buf));
new (buf) MyClassImpl {}; ...
}
MyClass::MyClassImpl& MyClass::impl() { return *(MyClass*)buf; }
void MyClass:Frob() { impl().myFieldA = ...; impl().myFieldB = ...; }
This has the big disavantage that either a lot of space is potentially
wasted in 'buf' or a global recompilation and abi break must be done
more often.
It is obvious how runtime arrays, as proposed by N4025 can immediately
help here:
// MyClass.h
struct MyClass {
MyClass()
...
private:
struct MyClassImpl;
const sizeof std::size_t size;
alignas(long) char buf[size];
...
};
//MyClass.cpp:
MyClass::MyClassImpl ... // As Before
MyClass::MyClass() : size{sizeof(MyClass:MyClassImpl)} {
static_assert(alignof(MyClassImpl) <= alignof(buf));
new (buf) MyClassImpl {}; ...
}
Unfortunately we sill need to explicitly set and test the alignment.
Another problem is that N4025 requires that no member function can be
used to initialize the size of [buf], so we have to go to the
superfluous special sizeof 'size' member. Alternatively, it might be
possible to use a static member function or even a global function to
compute the size.
In general the ability to treat dynamically sized objects as normal
objects is very powerful and goes beyond the possiblity of compilation
firewalls: think of all the type erasure wrappers that currently need
to dynamically allocate their wrapped object (std::function,
boost::any, adobe::any_iterator), if they were implemented as dynamic
sized types, not only they would save an allocation, but, after
inlining, allow for more powerful compiler optimizations.
My suggestion to the authors is to refocus the paper to cover more use
cases and to add additional syntax so that a larger part of the
community can benefit from the change.
I also would like to see a discussion of how return of variable sizes
can be implemented and if and how arrays of variable sized types can
be supported (sizeof could potentially become O(n)).
--
---
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_363_32856272.1401725183828
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br>Hi all,<br><br>As per title, I have some feedback on N=
4025.<br><br>For those who haven't read it yet, this paper allows for runti=
me sized<br>array members of structs; critically, it differentiates from ot=
her<br>proposals by not requiring the constructor to be inline. If I<br>und=
erstand correctly, space allocation is done by providing a two<br>phase con=
struction process for a class. At runtime a compiler<br>generated function,=
keyed on the constructor function, is<br>transparently called by the runti=
me to compute the (stack or heap)<br>allocation size. From the paper it is =
not clear how runtime sized<br>objects are returned or if they are allowed =
to be returned at all.<br><br>I'm not really sold on the syntax, in particu=
lar I think that the<br>runtime evaluated sizeof() might not fly with the m=
any in the<br>committee, but I'll leave the bike-shedding to others. I do l=
ike the<br>semantics in general and I would hope that it gets in the standa=
rd in<br>some form.<br><br>My use case is not really run time sized arrays,=
but an alternative to<br>compiler firewalls.<br><br>As most C++ programmer=
s know, on large codebases, is often desirable<br>to hide the implementatio=
n details of a class from its header file,<br>especially if the implementat=
ion details change often, to minimise the<br>amount of translation units th=
at need recompilation when an<br>implementation changes; similarly implemen=
tation hiding also allows<br>for more robust ABIs.<br><br>The way that hidi=
ng is currently implemented is either via published<br>base classes that de=
fine virtual functions implemented by unpublished<br>derived classes and th=
en delegating construction to factories, or via<br>the well known pimple id=
iom (a.k.a. letter/envelope): the actual<br>implementation is delegated to =
a private class which is not exposed to<br>client code, the published class=
only has a pointer to the<br>implementation class and forwards all its fun=
ctionality to it.<br><br>Both idioms have drawbacks, base classes and virtu=
al functions pretty<br>much require heap allocation, and virtual dispatch a=
dds some overhead,<br>while the pimple idiom, in addition to the extra indi=
rection (which<br>also requires heap allocation), requires writing a lot of=
boilerplate<br>code that does the forwarding.<br><br>A third solution is t=
o do away with the interface/implementation and<br>have the class contain o=
nly a single array of chars, sized big enough<br>to contain the actual impl=
ementation plus additional space:<br><br>// MyClass.h <br>struct MyClass {<=
br> MyClass(); <br> void Frob(); <br><br>private:<br> struct=
MyClassImpl; <br> MyClassImpl& impl();<br> alignas(long) cha=
r buf[1024]; <br>};<br><br><br>//MyClass.cpp: <br>MyClass::MyClassImpl {<br=
> long myFieldA; <br> long myFieldB;<br> int myFieldC; ..=
.. <br>};<br><br>MyClass::MyClass() { <br> static_assert(sizeof(=
MyClassImpl) <=3D sizeof(buf)); <br> static_assert(alignof(MyClass=
Impl) <=3D alignof(buf)); <br> new (buf) MyClassImpl {}; ... =
<br>}<br><br>MyClass::MyClassImpl& MyClass::impl() { return *(MyClass*=
)buf; }<br><br>void MyClass:Frob() { impl().myFieldA =3D ...; impl().myFiel=
dB =3D ...; }<br><br>This has the big disavantage that either a lot of spac=
e is potentially<br>wasted in 'buf' or a global recompilation and abi break=
must be done<br>more often.<br><br>It is obvious how runtime arrays, as pr=
oposed by N4025 can immediately<br>help here:<br><br>// MyClass.h <br><br>s=
truct MyClass {<br> MyClass()<br> ...<br>private:<br><br> st=
ruct MyClassImpl; <br> const sizeof std::size_t size;<br> alignas=
(long) char buf[size]; <br> ...<br>};<br><br><br>//MyClass.cpp: <br>My=
Class::MyClassImpl ... // As Before<br><br>MyClass::MyClass() : size{sizeof=
(MyClass:MyClassImpl)} { <br> static_assert(alignof(MyClassImpl) <=
=3D alignof(buf)); <br> new (buf) MyClassImpl {}; ... <br>}<br>=
<br>Unfortunately we sill need to explicitly set and test the alignment.<br=
><br>Another problem is that N4025 requires that no member function can be<=
br>used to initialize the size of [buf], so we have to go to the<br>superfl=
uous special sizeof 'size' member. Alternatively, it might be<br>possible t=
o use a static member function or even a global function to<br>compute the =
size.<br><br>In general the ability to treat dynamically sized objects as n=
ormal<br>objects is very powerful and goes beyond the possiblity of compila=
tion<br>firewalls: think of all the type erasure wrappers that currently ne=
ed<br>to dynamically allocate their wrapped object (std::function,<br>boost=
::any, adobe::any_iterator), if they were implemented as dynamic<br>sized t=
ypes, not only they would save an allocation, but, after<br>inlining, allow=
for more powerful compiler optimizations.<br><br>My suggestion to the auth=
ors is to refocus the paper to cover more use<br>cases and to add additiona=
l syntax so that a larger part of the<br>community can benefit from the cha=
nge.<br><br>I also would like to see a discussion of how return of variable=
sizes<br>can be implemented and if and how arrays of variable sized types =
can<br>be supported (sizeof could potentially become O(n)).<br></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_363_32856272.1401725183828--
.
Author: Richard Smith <richard@metafoo.co.uk>
Date: Mon, 2 Jun 2014 11:53:12 -0700
Raw View
--20cf3079bff238690904fadee817
Content-Type: text/plain; charset=UTF-8
On Mon, Jun 2, 2014 at 9:06 AM, Giovanni Piero Deretta <gpderetta@gmail.com>
wrote:
>
> Hi all,
>
> As per title, I have some feedback on N4025.
>
Thanks a lot for your comments!
> For those who haven't read it yet, this paper allows for runtime sized
> array members of structs; critically, it differentiates from other
> proposals by not requiring the constructor to be inline. If I
> understand correctly, space allocation is done by providing a two
> phase construction process for a class. At runtime a compiler
> generated function, keyed on the constructor function, is
> transparently called by the runtime to compute the (stack or heap)
> allocation size. From the paper it is not clear how runtime sized
> objects are returned or if they are allowed to be returned at all.
>
> I'm not really sold on the syntax, in particular I think that the
> runtime evaluated sizeof() might not fly with the many in the
> committee, but I'll leave the bike-shedding to others.
>
The runtime sizeof concern is a great point, and one which we spent some
time agonizing over.
There are two different flavours of objection to runtime-evaluated sizeof:
* sizeof(expr) is no longer always a constant expression
* sizeof(expr) might have side-effects, and might evaluate its operand.
Our paper admits defeat on the first of these, but we believe we can
address the second objection.
Part of the notional model is that bound-expressions can be evaluated
(repeatedly) at any point during the lifetime of a object with a
runtime-bound array data member (technically, during a period slightly
longer than the lifetime of the object, at both ends). Therefore
sizeof(expr) doesn't evaluate any bound-expressions that could not be
evaluated at that point anyway. (We didn't completely formalize this rule,
and don't precisely say when we'll evaluate bound-expressions, but the
intention is that the implementation gets to pick when they are evaluated.)
We also intend for there to be restrictions on the form of 'expr' in
'sizeof(expr)' in the case where it has a runtime-size type. We would most
likely restrict 'expr' to be either an id-expression or an explicit type
conversion expression (either 'T(...)' or 'T{...}').
The combination of these restrictions results in only bound-expressions
being evaluated by a sizeof-expression (and bound-expressions could be
evaluated at that point anyway).
The syntax is a strawman, and as noted in section 4.1, we think it's
premature to get too focused on it at this stage.
I do like the
> semantics in general and I would hope that it gets in the standard in
> some form.
>
> My use case is not really run time sized arrays, but an alternative to
> compiler firewalls.
>
> As most C++ programmers know, on large codebases, is often desirable
> to hide the implementation details of a class from its header file,
> especially if the implementation details change often, to minimise the
> amount of translation units that need recompilation when an
> implementation changes; similarly implementation hiding also allows
> for more robust ABIs.
>
> The way that hiding is currently implemented is either via published
> base classes that define virtual functions implemented by unpublished
> derived classes and then delegating construction to factories, or via
> the well known pimple idiom (a.k.a. letter/envelope): the actual
> implementation is delegated to a private class which is not exposed to
> client code, the published class only has a pointer to the
> implementation class and forwards all its functionality to it.
>
> Both idioms have drawbacks, base classes and virtual functions pretty
> much require heap allocation, and virtual dispatch adds some overhead,
> while the pimple idiom, in addition to the extra indirection (which
> also requires heap allocation), requires writing a lot of boilerplate
> code that does the forwarding.
>
> A third solution is to do away with the interface/implementation and
> have the class contain only a single array of chars, sized big enough
> to contain the actual implementation plus additional space:
>
> // MyClass.h
> struct MyClass {
> MyClass();
> void Frob();
>
> private:
> struct MyClassImpl;
> MyClassImpl& impl();
> alignas(long) char buf[1024];
> };
>
>
> //MyClass.cpp:
> MyClass::MyClassImpl {
> long myFieldA;
> long myFieldB;
> int myFieldC; ...
> };
>
> MyClass::MyClass() {
> static_assert(sizeof(MyClassImpl) <= sizeof(buf));
> static_assert(alignof(MyClassImpl) <= alignof(buf));
> new (buf) MyClassImpl {}; ...
> }
>
> MyClass::MyClassImpl& MyClass::impl() { return *(MyClass*)buf; }
>
> void MyClass:Frob() { impl().myFieldA = ...; impl().myFieldB = ...; }
>
> This has the big disavantage that either a lot of space is potentially
> wasted in 'buf' or a global recompilation and abi break must be done
> more often.
>
> It is obvious how runtime arrays, as proposed by N4025 can immediately
> help here:
>
> // MyClass.h
>
> struct MyClass {
> MyClass()
> ...
> private:
>
> struct MyClassImpl;
> const sizeof std::size_t size;
> alignas(long) char buf[size];
> ...
> };
>
>
> //MyClass.cpp:
> MyClass::MyClassImpl ... // As Before
>
> MyClass::MyClass() : size{sizeof(MyClass:MyClassImpl)} {
> static_assert(alignof(MyClassImpl) <= alignof(buf));
> new (buf) MyClassImpl {}; ...
> }
>
> Unfortunately we sill need to explicitly set and test the alignment.
>
This is not entirely essential: you can make 'buf' be of size
sizeof(MyClassImpl) + alignof(MyClassImpl) - 1, and use the
appropriately-aligned sequence of sizeof(MyClassImpl) characters as your
buffer. However, in practice, it's probably better to hardcode an alignment
to avoid excess allocation and pointer adjustment. (Either way, this logic
can all be wrapped inside a better_pimpl class template, so it only needs
to be written once.)
Another problem is that N4025 requires that no member function can be
> used to initialize the size of [buf], so we have to go to the
> superfluous special sizeof 'size' member. Alternatively, it might be
> possible to use a static member function or even a global function to
> compute the size.
>
This is merely imprecise wording in the paper: we intend to allow a static
member function to be used here. The only issue is that a bound-expression
cannot in general use the values of subobjects of 'this', because
bound-expressions can be evaluated before such an object exists.
In general the ability to treat dynamically sized objects as normal
> objects is very powerful and goes beyond the possiblity of compilation
> firewalls: think of all the type erasure wrappers that currently need
> to dynamically allocate their wrapped object (std::function,
> boost::any, adobe::any_iterator), if they were implemented as dynamic
> sized types, not only they would save an allocation, but, after
> inlining, allow for more powerful compiler optimizations.
>
> My suggestion to the authors is to refocus the paper to cover more use
> cases and to add additional syntax so that a larger part of the
> community can benefit from the change.
>
Noted. But you should be aware that this paper is meant as an exploration
of a design option for runtime bound data members, which the committee is
already considering in the context of the Array Extensions TS. Previous
papers and discussions have already covered, to some extent, the value
proposition in supporting such a feature.
I also would like to see a discussion of how return of variable sizes
> can be implemented and if and how arrays of variable sized types can
> be supported (sizeof could potentially become O(n)).
>
These are both interesting issues, and are important to the composability
of this feature.
Returning objects of runtime size can be supported in principle (for
instance, the caller can provide a fixed-size buffer, and the callee can
use heap allocation if the buffer is insufficient; after the call, the
caller can check the size of the returned object and shrink its buffer or
detect that it needs to free the object). A future version of the paper
will need to cover this, if the committee is in favor of pursuing the
direction of this paper.
Section 6.9 has our very brief response to arrays of runtime-sized types.
We think hiding too much runtime cost behind built-in array indexing
notation would be a disservice to programmers (in particular, arr[i] would
be O(i) if 'arr' is an array of a runtime-sized type that is laid out in
memory like a normal array). However, there's no real problem with
multidimensional arrays of runtime bound as members of a runtime-sized
class.
--
---
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/.
--20cf3079bff238690904fadee817
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On M=
on, Jun 2, 2014 at 9:06 AM, Giovanni Piero Deretta <span dir=3D"ltr"><<a=
href=3D"mailto:gpderetta@gmail.com" target=3D"_blank">gpderetta@gmail.com<=
/a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr"><br>Hi all,<br><br>As per t=
itle, I have some feedback on N4025.<br></div></blockquote><div><br></div><=
div>
Thanks a lot for your comments!</div><div>=C2=A0</div><blockquote class=3D"=
gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-=
left:1ex"><div dir=3D"ltr">For those who haven't read it yet, this pape=
r allows for runtime sized<br>
array members of structs; critically, it differentiates from other<br>propo=
sals by not requiring the constructor to be inline. If I<br>understand corr=
ectly, space allocation is done by providing a two<br>phase construction pr=
ocess for a class. At runtime a compiler<br>
generated function, keyed on the constructor function, is<br>transparently =
called by the runtime to compute the (stack or heap)<br>allocation size. Fr=
om the paper it is not clear how runtime sized<br>objects are returned or i=
f they are allowed to be returned at all.<br>
<br>I'm not really sold on the syntax, in particular I think that the<b=
r>runtime evaluated sizeof() might not fly with the many in the<br>committe=
e, but I'll leave the bike-shedding to others.</div></blockquote><div>
<br></div><div>The runtime sizeof concern is a great point, and one which w=
e spent some time agonizing over.</div><div><br></div><div>There are two di=
fferent flavours of objection to runtime-evaluated sizeof:</div><div><br>
</div><div>=C2=A0* sizeof(expr) is no longer always a constant expression</=
div><div>=C2=A0* sizeof(expr) might have side-effects, and might evaluate i=
ts operand.</div><div><br></div><div>Our paper admits defeat on the first o=
f these, but we believe we can address the second objection.</div>
<div><br></div><div>Part of the notional model is that bound-expressions ca=
n be evaluated (repeatedly) at any point during the lifetime of a object wi=
th a runtime-bound array data member (technically, during a period slightly=
longer than the lifetime of the object, at both ends). Therefore sizeof(ex=
pr) doesn't evaluate any bound-expressions that could not be evaluated =
at that point anyway. (We didn't completely formalize this rule, and do=
n't precisely say when we'll evaluate bound-expressions, but the in=
tention is that the implementation gets to pick when they are evaluated.)</=
div>
<div><br></div><div>We also intend for there to be restrictions on the form=
of 'expr' in 'sizeof(expr)' in the case where it has a run=
time-size type. We would most likely restrict 'expr' to be either a=
n id-expression or an explicit type conversion expression (either 'T(..=
..)' or 'T{...}').</div>
<div><br></div><div>The combination of these restrictions results in only b=
ound-expressions being evaluated by a sizeof-expression (and bound-expressi=
ons could be evaluated at that point anyway).</div><div><br></div><div>
<br></div><div>The syntax is a strawman, and as noted in section 4.1, we th=
ink it's premature to get too focused on it at this stage.</div><div><b=
r></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border=
-left:1px #ccc solid;padding-left:1ex">
<div dir=3D"ltr">I do like the<br>semantics in general and I would hope tha=
t it gets in the standard in<br>some form.<br><br>My use case is not really=
run time sized arrays, but an alternative to<br>compiler firewalls.<br><br=
>
As most C++ programmers know, on large codebases, is often desirable<br>to =
hide the implementation details of a class from its header file,<br>especia=
lly if the implementation details change often, to minimise the<br>amount o=
f translation units that need recompilation when an<br>
implementation changes; similarly implementation hiding also allows<br>for =
more robust ABIs.<br><br>The way that hiding is currently implemented is ei=
ther via published<br>base classes that define virtual functions implemente=
d by unpublished<br>
derived classes and then delegating construction to factories, or via<br>th=
e well known pimple idiom (a.k.a. letter/envelope): the actual<br>implement=
ation is delegated to a private class which is not exposed to<br>client cod=
e, the published class only has a pointer to the<br>
implementation class and forwards all its functionality to it.<br><br>Both =
idioms have drawbacks, base classes and virtual functions pretty<br>much re=
quire heap allocation, and virtual dispatch adds some overhead,<br>while th=
e pimple idiom, in addition to the extra indirection (which<br>
also requires heap allocation), requires writing a lot of boilerplate<br>co=
de that does the forwarding.<br><br>A third solution is to do away with the=
interface/implementation and<br>have the class contain only a single array=
of chars, sized big enough<br>
to contain the actual implementation plus additional space:<br><br>// MyCla=
ss.h <br>struct MyClass {<br>=C2=A0MyClass(); <br>=C2=A0void Frob(); <br><b=
r>private:<br>=C2=A0struct MyClassImpl; <br>=C2=A0MyClassImpl& impl();<=
br>=C2=A0alignas(long) char buf[1024]; <br>
};<br><br><br>//MyClass.cpp: <br>MyClass::MyClassImpl {<br>=C2=A0 long myFi=
eldA; <br>=C2=A0 long myFieldB;<br>=C2=A0 int myFieldC; ...=C2=A0 <br>};<br=
><br>MyClass::MyClass() { <br>=C2=A0 static_assert(sizeof(MyClassImpl) <=
=3D sizeof(buf)); <br>=C2=A0 static_assert(alignof(MyClassImpl) <=3D ali=
gnof(buf)); <br>
=C2=A0 new (buf) MyClassImpl {}; ...=C2=A0 <br>}<br><br>MyClass::MyClassImp=
l& MyClass::impl() { return *(MyClass*)buf; }<br><br>void MyClass:Frob(=
) { impl().myFieldA =3D ...; impl().myFieldB =3D ...; }<br><br>This has the=
big disavantage that either a lot of space is potentially<br>
wasted in 'buf' or a global recompilation and abi break must be don=
e<br>more often.<br><br>It is obvious how runtime arrays, as proposed by N4=
025 can immediately<br>help here:<br><br>// MyClass.h <br><br>struct MyClas=
s {<br>
=C2=A0MyClass()<br>=C2=A0...<br>private:<br><br>=C2=A0struct MyClassImpl; <=
br>=C2=A0const sizeof std::size_t size;<br>=C2=A0alignas(long) char buf[siz=
e]; <br>=C2=A0...<br>};<br><br><br>//MyClass.cpp: <br>MyClass::MyClassImpl =
.... // As Before<br><br>MyClass::MyClass() : size{sizeof(MyClass:MyClassImp=
l)} { <br>
=C2=A0 static_assert(alignof(MyClassImpl) <=3D alignof(buf)); <br>=C2=A0=
new (buf) MyClassImpl {}; ...=C2=A0 <br>}<br><br>Unfortunately we sill nee=
d to explicitly set and test the alignment.<br></div></blockquote><div><br>=
</div><div>This is not entirely essential: you can make 'buf' be of=
size sizeof(MyClassImpl) + alignof(MyClassImpl) - 1, and use the appropria=
tely-aligned sequence of sizeof(MyClassImpl) characters as your buffer. How=
ever, in practice, it's probably better to hardcode an alignment to avo=
id excess allocation and pointer adjustment. (Either way, this logic can al=
l be wrapped inside a better_pimpl class template, so it only needs to be w=
ritten once.)</div>
<div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex=
;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">Another prob=
lem is that N4025 requires that no member function can be<br>used to initia=
lize the size of [buf], so we have to go to the<br>
superfluous special sizeof 'size' member. Alternatively, it might b=
e<br>possible to use a static member function or even a global function to<=
br>compute the size.<br></div></blockquote><div><br></div><div>This is mere=
ly imprecise wording in the paper: we intend to allow a static member funct=
ion to be used here. The only issue is that a bound-expression cannot in ge=
neral use the values of subobjects of 'this', because bound-express=
ions can be evaluated before such an object exists.</div>
<div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex=
;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">In general t=
he ability to treat dynamically sized objects as normal<br>objects is very =
powerful and goes beyond the possiblity of compilation<br>
firewalls: think of all the type erasure wrappers that currently need<br>to=
dynamically allocate their wrapped object (std::function,<br>boost::any, a=
dobe::any_iterator), if they were implemented as dynamic<br>sized types, no=
t only they would save an allocation, but, after<br>
inlining, allow for more powerful compiler optimizations.<br><br>My suggest=
ion to the authors is to refocus the paper to cover more use<br>cases and t=
o add additional syntax so that a larger part of the<br>community can benef=
it from the change.<br>
</div></blockquote><div><br></div><div>Noted. But you should be aware that =
this paper is meant as an exploration of a design option for runtime bound =
data members, which the committee is already considering in the context of =
the Array Extensions TS. Previous papers and discussions have already cover=
ed, to some extent, the value proposition in supporting such a feature.</di=
v>
<div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex=
;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">I also would=
like to see a discussion of how return of variable sizes<br>can be impleme=
nted and if and how arrays of variable sized types can<br>
be supported (sizeof could potentially become O(n)).</div></blockquote><div=
><br></div><div>These are both interesting issues, and are important to the=
composability of this feature.</div><div><br></div><div>Returning objects =
of runtime size can be supported in principle (for instance, the caller can=
provide a fixed-size buffer, and the callee can use heap allocation if the=
buffer is insufficient; after the call, the caller can check the size of t=
he returned object and shrink its buffer or detect that it needs to free th=
e object). A future version of the paper will need to cover this, if the co=
mmittee is in favor of pursuing the direction of this paper.</div>
<div><br></div><div>Section 6.9 has our very brief response to arrays of ru=
ntime-sized types. We think hiding too much runtime cost behind built-in ar=
ray indexing notation would be a disservice to programmers (in particular, =
arr[i] would be O(i) if 'arr' is an array of a runtime-sized type t=
hat is laid out in memory like a normal array). However, there's no rea=
l problem with multidimensional arrays of runtime bound as members of a run=
time-sized class.</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 />
--20cf3079bff238690904fadee817--
.
Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sun, 8 Jun 2014 15:52:26 -0700 (PDT)
Raw View
------=_Part_248_30244795.1402267946760
Content-Type: text/plain; charset=UTF-8
I think that the work towards allowing variable length arrays in C++
is very important, as it reinforces the performance advantage of C++
over other languages. After all, the number of memory allocations
have a large performance impact and the lack of VLAs is a major
reason for allocations in C++.
The main problem with having VLAs in objects is how to calculate the
size before the object's memory is allocated. This is necessary to be
able to keep a heap allocated object in one malloc block.
The solution offered by N4025 lays a large burden on both the
programmer and the compiler:
The programmer needs to annotate both the constructor parameters used
in the bounds expressions and the members used to store the bounds
after construction. Compilers need to calculate the bounds value
twice using different code, in the first phase to some stack variable
that represents the bounds member and then again to actually set up
its value in phase 2. There are also a plethora of error conditions
that the compiler needs to check for, such as programmers forgetting
to annotate parameters or members or make them non-const.
My proposal gets rid of this hazzle by leaving the constructor
parameters on the stack between the phases. While this may seem scary
at first, after looking at it in detail I find it quite reasonable. A
lot of the results of my investigation are presented below.
My design goals were a little different than those of N4025:
I didn't want to add special syntax for bound expressions
or bound-expression-participating members. Instead I wanted the
intuitive syntax of putting the array bound initializing
expression in the constructor initializer list, without forcing the
constructors to be inline. Also I didn't allow the implementation to
evaluate the bounds expressions more than once.
To accomplish this I suggest a multi phase construction system which
works like this:
0. Allocate space for the actual object to be constructed if it has
stack storage class.
1. Save the stack pointer. Probably in a register that
the calling convention requires to be saved.
2. Call the first phase constructor which evaluates all
constructor expressions for subobjects with VLAs and all VLA bounds
expressions and returns the total number of bytes required for all
VLA elements.
3. Allocate memory for the object + VLA elements (heap
case) or just the VLA elements (static and automatic cases).
4. Call the second phase constructor with three pointers: The object
'this' pointer, the VLA memory start address and the saved stack
pointer from step 1. The second phase constructor can find the
pre-calculated constructor parameters and VLA bounds using the saved
stack pointer and sets up the object, pointing the VLA pointers into the
allocated memory.
5.Call the third phase constructor which just destroys
all the values saved in phase 1. This phase is also used in case of a
constructor exception and in sizeof.(unevaluated context).
One drawback of this system is that the order of evaluation of
constructor expressions is somewhat surprising: All constructor
parameters for objects with VLAs are evaluated _before_ those of
non-VLA subobjects. The strict LIFO order of construction/destruction
is however kept, so in normal circumstances this should not be a
problem. Note that this does not affect objects without VLAs in them,
so there is no backwards compatiblity issue.
Another issue may be that this system basically requires VLA elements
to be stored in a separate side stack and not in the normal stack.
This is as otherwise the memory used for constructor parameter values
would be "trapped" under the VLA elements on the stack until the VLA
object is popped. While this need increases the complexity of the runtime
system it also has the advantage that the risk of stack overflow is
greatly reduced as the side stack can easily be segmented. As the
basic idea with VLAs is to move heap data to the stack the risk of
overflow is otherwise changed from too deep recursions to too large
data sets.
Finally, as there is no object yet in phase 1 it can't be permitted
to use non-static members in subobject constructor expressions for
subobjects with VLAs. This is bad practice anyway but is of course
used today in some code. Again, as this limitation applies only to
subobjects with VLAs it is not a breaking change, but unfortunate as
we must have different rules depending on whether the subobject has
VLAs or not. Also it can be quite hard for the compiler to figure out
if member data is actually used unless it is also forbidden to call
non-static methods.
Here is an example whoing the problem: two_arrays constructor mutates its
parameters.
struct bg_array {
bg_array(size_t sz) : m_data[sz] {
for (size_t i = 0; i < sz; i++)
m_data[i] = 0;
}
int m_data[];
};
struct two_arrays {
two_arrays(int sz1, int sz2) : first(++sz1), second(++sz2) {}
bg_array first, second;
};
two_arrays v(10, 20);
Here it is quite evident that it is not allowed to evaluate the
constructor parameters more than once, as the sz1 and sz2 would be
incremented twice, and the array size would not be the same as the loop
count of the initiation!
The inside of a reference implementation:
----------------------------------------
Here is pseudo-code for the example above which I wrote to make sure this
system could work.
The v construction call site code is something like this (assuming v
is a static variable and sp is a pointer to the stack):
// Object memory reservation not needed as v is in static storage.
// Setup constructor argument values as usual. These could be complex
expressions of course.
*reinterpret_cast<int*>(sp) = 10;
sp += sizeof(int);
*reinterpret_cast<int*>(sp) = 20;
sp += sizeof(int);
// Here the three phases of the constructor are called and the memory
itself allocated. There will be just small variations here
// depending on the storage class:
char* tmpfp = sp; // Save stack pointer after ctor parameters are pushed.
size_t mem_size = two_arrays::two_arrays_phase1(sp); // Calculate memory
size and save values on stack.
char* vdata = staticallocator.alloc(mem_size); // Get the memory required
from the special static VLA data stack. __atexit code will free this memory
(if needed)
two_arrays::two_arrays_phase2(sp, &v, vdata, tmpfp); // Perform the real
construction at v, allocating VLAs from vdata, with tmpfp indicating where
ctor expression values and array sizes are.
two_arrays::two_arrays_phase3(sp); // Destroy ctor parameter values and get
rid of array size values. Restore sp.
The different phases of the two_arrays constructor:
size_t two_arrays_phase1(char*& sp)
{
char* fp = sp;
// Evaluate constructor expressions for 'first' ctor
*reinterpret_cast<size_t*>(sp) = ++*reinterpret_cast<int*>(fp - 2 * sizeof(
int));
sp += sizeof(size_t);
// Call phase 1 for 'first'
size_t ret = bg_array_phase1(sp);
// Evaluate constructor expressions for 'second' ctor
// NOTE: fp is necessary as we don't know how much bg_array_phase1 moves
sp.
*reinterpret_cast<size_t*>(sp) = ++*reinterpret_cast<int*>(fp - sizeof(int
));
sp += sizeof(size_t);
// Call phase 1 for 'second' and sum up the memory use.
ret += bg_array_phase1(sp);
// NOTE: No decrement of stack pointer!
return ret;
}
void two_arrays_phase2(char* sp, char* object, char*& memoryblock, char*&
tmpfp)
{
// Call phase two of members. Their code will affect memoryblock and
tmpfp pointers but not sp.
bg_array_phase2(sp, object + offsetof(two_arrays, first), memoryblock,
tmpfp);
bg_array_phase2(sp, object + offsetof(two_arrays, second), memoryblock,
tmpfp);
}
void two_arrays_phase3(char*& sp)
{
bg_array_phase3(sp); // destroy 'second' ctor parameter
bg_array_phase3(sp); // destroy 'first' ctor parameter
// Destroy my constructor expression values in reverse order
sp -= sizeof(int);
*reinterpret_cast<int*>(sp).~int(); // sz2
sp -= sizeof(int);
*reinterpret_cast<int*>(sp).~int(); // sz1
}
The the bg_array code looks like this, assuming that a VLA is represented
by a begin and end pointer.
size_t bg_array_phase1(char*& sp)
{
char* fp = sp;
// Calculate the VLA size in bytes. This expression can be complex and is
free to use the stack.
*reinterpret_cast<size_t*>(sp) = *reinterpret_cast<size_t*>(fp - sizeof(
size_t)) * sizeof(int);
sp += sizeof(size_t);
// Return the amount of memory needed.
return *reinterpret_cast<size_t*>(fp);
}
void bg_array_phase2(char* sp, char* object, char*& memoryblock, char*&
tmpfp) // tmpfp is the sp value from phase1
{
// Setup VLA members, assumed to be two pointers, to begin and end.
*reinterpret_cast<int**>(object + offsetof(bg_array, m_data)) =
reinterpret_cast<int*>(memoryblock);
memoryblock += reinterpret_cast<size_t*>(tmpfp); // Add precalculated
array size in bytes set in phase 1.
*reinterpret_cast<int**>(object + offsetof(bg_array, m_data) + sizeof(int
*)) = reinterpret_cast<int*>(memoryblock);
// Implementation of the constructor body. The access of sz (the
constructor parameter) is via the tmpfp pointer. Any storage required to
implement the loop
// is allocated at sp as usual. The offset between the two is not known
here!
for (size_t i = 0; i < *reinterpret_cast<size_t*>(tmpfp - sizeof(size_t));
i++)
m_data[i] = 0;
// Increment tmpfp as sp was incremented in phase1.
tmpfp += sizeof(size_t);
}
size_t bg_array_phase3(char*& sp)
{
sp -= sizeof(size_t); // Pass the VLA size
// Destroy my ctor parameter.
sp -= sizeof(size_t);
*reinterpret_cast<int*>(sp).~size_t();
}
Sizeof decoration
-----------------
While I don't like the extra syntax required in N4025 it does have
some merit to be able to specify to the compiler how to store the
size information of a VLA, as it can improve performance or reduce
memory use somewhat.
My belief is however that this syntax should be optional so that
there is a fallback representation that the compiler uses when no
bounds expression is written. This representation is most likely a
two pointer begin/end notation as this has proven to be the best for
vector (at least that's whats being used).
Personally I have not ever felt a desire for having the size of a
vector stored in any particular way, using begin/end or size() is
just fine and even if you are lazy enough to use index based loops
instead of iterator based loops the compiler is often smart enough to
eradicate the difference. My point is that the same indifference to
how the size is stored is probably going to be prevalent for VLAs
too, which makes the inclusion of the rather complicated sizeof
decoration and bounds expressions questionable.
Interpretation of sizeof
------------------------
It seems logical that sizeof() on classes containing VLAs include the
memory taken by these as there is a need for placement new to know
how much memory to allocate. The idea of using sizeof(Class(pars)) is
useful for this case, and it can be implemented by just calling phase
1 and 3 of the constructor without calling phase 2. This does not
instantiate the type but evaluates the constructor expressions once,
as expected. (Less expected for nested objects with VLAs though, but
necessary).
Doing sizeof on a preexisting object with VLA(s) or on a VLA itself
should probably calculate the size in bytes based on the actual array
lengths. As this can be somewhat complicated it is reasonable that a
function to do this is compiled as a separate entity for each class
with VLAs, so that the sizeof() can just make a simple function call.
Inlining this function is often reasonable and all the required
information to do so is available to the compiler as you need to have
seen the full class head to be able to do sizeof on an object anyway.
The usefulness of this operation is rather questionable, but not to
complicate the language specification with another special case it
should probably be allowed. A caveat to this idea is presented below
when function paramters are discussed.
This said there needs to be a way to determine the size of a VLA in
elements. It is logical that the std::begin() and std:end() functions
should be automagically overloaded for VLAs as the basis for this.
Then std::end(vla) - std::begin(vla) returns the size in elements and
range based for and stl algorithms work as expected.
A free function could be added for general sizing use:
template<typename T> size_t std::size(const T& obj)
{
return std::end(obj) - std::begin(obj);
}
To get the minimum size of an object of a class type with VLA you can
use sizeof(ClassName) to get the size without VLA data. Likewise you
can use sizeof(T[]) to get the size of the array "head" i.e. 2 *
sizeof(void*) or similar. NOTE: This could be a breaking change if
sizeof(T[]) is today specified to return the same as sizeof(T*). If
so the committe must decide which way to go. This is not so important
as it could also be specified that the size of a VLA "head" is the
same as two pointers in writing in the standard.
Destroying objects with VLAs
----------------------------
Destroying objects with VLAs must take note of the storage class of
the object. This does not affect the destructor per se, as it never
deletes the memory used, only runs the destructors of the members
(including VLA elements).
It is instead the responsibility of the callsite to deallocate the
memory of the VLA elements as well as the object itself. For the heap
case this is likely done by just one free() operation while on the
stack it would involve popping both the main and side stacks. To pop
the side stack by an appropriate amount the begin pointer of the
first VLA and/or the end pointer of the last VLA element must be
accessed.
Note that it is very likely that the side stack can't be a pure LIFO
stack but it is probably good enough to have a used bit in each
allocated block and then pop all trailing unused blocks, the locked
in blocks are normally short lived. If VLA element blocks above a
certain treshold size are allocated directly on the heap such blocks
don't get locked in so no really big unused holes in the side
stack can occur.
Copying objects with VLAs
-------------------------
Following the convention of arrays in C++ objects in general copying
of VLA members should be a deep copy. This means that the auto
generated copy constructor of a clas with a VLA must inspect the
incoming source object in phase 1 to find the sizes of its VLAs.
A user defined copy constructor must set up the sizes of the object's
VLA as any other constructor and typically would do this by checking
the source object.
I don't remember if there is a suggestion to allow defering to the
default implementation for the copy construction and then "add some"
but it would surely be of interest (this is a side track):
MyClass::MyClass(const MyClass& src) : default(src) { -- do some checks on
consistency for instance -- }
Moving objects with VLAs
------------------------
Moving objects with VLAs is only possible in special circumstances. I
think that in general no move constructor or assignment operator
should be auto-generated for classes with VLAs. There are some
specific but useful cases where moving would be possible so there
should be writings that the compiler is allowed to elide the copying
of the object in certain situations such as function returns. It then
becomes a quality of implementation issue when such elison is made by
a particular compiler.
An example of why it is harder to reuse the VLA elements than one may
think is presented below for the return case.
Returning VLAs and objects with VLAs
------------------------------------
An object returned from a function is eligible for moving to a
destination rather than copying. For VLAs this moving presents a
unique problem as there is an uncertainty on the storage class to use
for the VLA elements to make the move possible.
Returning a plain VLA is probably not to be allowed as returning a
sized array is not allowed. If returning arrays is to become allowed
in the future the discussion below for objects containing VLAs can be
extended to this case.
Following the standard C++ conventions the object returned is of
course on the stack, and thus its VLA elements should be on the side
stack. But can they be moved into the receiving object? This is far
from obvious, as can be seen by the example below.
struct vla_class {
vla_class(int sz) : vla[sz] {
int i;
for (auto& x: vla)
x = i++;
}
int vla[];
};
vla_class my_function()
{
return vla_class(3);
}
struct outer {
outer(vla_class v, int x) : x[x], vlav(v) {}
float x[];
vla_class vlac;
}
void main()
{
outer obj(my_function(), 3);
}
Now, following the three phase system the constructor arguments for
outer::outer are first evaluated. This means that my_function gets
called already in phase 1 and returns the vla_class object which is
stored in the stack until phase 2. The phase 1 ctor for outer is then
called and finds that the vlac member is to be copy constructed so
can see its size. (BTW: Would this code even be allowed by N4025?).
It now seems possible that the VLA elements on the side stack could
be moved to the vlac member. The problem is when obj is ultimately
destroyed. At this time the x elements and VLA elements are not
contiguous in the side stack and need to be separately freed from it,
while in the normal case (for instance for an outer on the heap) only
one such free-up operation needs to be done. If the outer ctor phase
1 is in another module it can't know that the VLA elements of the
vla_class returned from my_function are available for elison, and
must thus request the full size memory block for all VLA elements.
At the same time there are plenty of cases where it is possible to
move the elements (for instance if the x member of outer is removed
above) and constructors are inline. And also, by tracking the
lifetime of the outer object the compiler can actually generate
special code to do the two free up operations for this particular
instance of outer, as this freeing is the responsibility of the call
site anyway.
Thus as for moving in general it seems reasonable to allow compilers
to do this type of optimization at will (return elision) just as for
other types of objects.
Passing VLAs as function parameters
-----------------------------------
My suggestion on this topic is that the function parameter type T x[]
which is today the same as T* is redefined to be different in that
both the begin and end of the actual parameter are passed in to the
function. For backwards compatibility it must unfortunately be
allowed to use a pointer as the actual parameter to such a formal but
in this case the pointer can be pushed twice (both as the begin and
end values). This means that for old functions (which obviously don't
do end() on the array parameter) work as always while new functions
interpret the pointer as an empty range. A recompile will however be
necessary which could present some problems with dlls compiled with
different compiler versions. Various changes in library
implementation regularly breaks ABIs between compiler versions anyway
so I don't think this is a serious concern.
One source of breaking changes with this could be if user code uses
sizeof(x). Previously this always returned the size of a pointer
while now it will return the size in bytes of the entire array.
Remaining question is what the result of that sizeof can reasonably
have been used for... On the other hand, as begin() and end() work
for VLAs there is little need for a sizeof() so maybe it can still
return the size of a pointer!
Due to this problem it is likely that VLA function parameters would
not be allowed in variable number function parameter lists (...) as
the macros used to handle those rely on the sizeof being correct when
bumping the stack pointer.
There is of course a slight performance penalty for this change,
incurred also for old functions (the pushing of the end value) but I
think this is acceptable comparing to the big upside for new
functions (and in case of trouble the old function can be changed to
take a T* instead).
void my_func(int x[])
{
for(auto i : x)
cout << i;
}
This now actually works as expected!
There is the issue of what to do in a mismatch situation, i.e. when
calling a function that takes a fixed size array with a mismatching
VLA. In this case, just as today, we just pass the begin pointer to
the function. No error. We can't know that it is an error to send in
a longer VLA to a function that wants a shorter, fixed size, array.
We can't even know that sending in a too short array is a problem,
the function maybe doesn't use all of its parameter...
Note that at least on VS2013 you can't do a range based for on a
fixed size array parameter as the compiler has forgotten the size. I
think that if range based for is fixed to work for variable size
array parameters it is reasonable to change the language so that it
is allowed for fixed size array parameters too.
Array slices as VLA parameters
------------------------------
If we get the possibility to send a VLA to a function and use its
size inside it would of course be nice to be able to slice the array,
i.e. to offset its begin value and reduce its end value. With the
suggestions so far presented this is not possible.
However, it would be feasible to allow casting of a VLA to another
array type, including one with a runtime size. This goes also for a
fixed size array and a pointer:
int sz = 56;
int my_vla[sz];
int my_arr[56];
int* my_ptr = my_arr;
vector<int> my_vec;
// Use slice from 10 to 20 based on these:
int smallsz = 10;
my_func(reinterpret_cast<int[smallsz]>(my_vla + 10)); // Use array->pointer
decay first.
my_func(reinterpret_cast<int[smallsz]>(my_arr + 10)); // Use array->pointer
decay first.
my_func(reinterpret_cast<int[smallsz]>(my_ptr + 10));
my_func(reinterpret_cast<int[my_vec.size()]>(my_vec.data()));
What's bizarre about this is of course the use of a non-const
expression inside the <> of the reinterpret_cast. This is rather
counter-intuitive, but in line with the already suggested extension
of sizeof. It is possible that this should be allowed for static cast
too, and even dynamic_cast<> could be reused to do this "safely" i.e.
to check that we are not increasing the size beyond the parameter's
size. I don't see how this could be differentiated between the
"throw" and "nullptr" results if such a cast fails though.
It could be better syntactically to introduce a new magic function in
std:
template<typename T> ***T[]*** slice(T* start, size_t size)
{
... something ...
}
This is a magic function as the return type is not a VLA by value
(it doesn't own the VLA elements), nor is it by reference as there is no
VLA pointer pair to refer to!
The copying logic for VLAs is also the same as other arrays when in
objects, that is, they are copied deeply. By wrapping a VLA into a
simple object value semantics can thus be achieved.
Exception unwinding
-------------------
Constructor expression values are now stored on the stack between the
first and third phase of the construction. Exception unwinding during
construction has to take this into account, but this is rather easy.
Exceptions during phase 1 are unwound like for any set of values
being pushed on the stack.
Exceptions during memory allocation or phase 2 must make sure to
destroy all the parameters by calling phase 3.
Exceptions during phase 3 are destructor exceptions and thus basically UB.
Multidimensional VLAs
---------------------
Rectangular VLAs of any number of dimensions should not be any
problem to define. Without additional compiler support the
implementation will be an array of VLAs, i.e. pointer pairs. This is
less efficient and less space efficient than need be. I think it
could be a quality of implementation issue if this basic layout is
used or if multidimensional VLAs get special treatment to reduce the
overhead.
Such a multidimensional VLA data structure will require more data
members, i.e. sizes for all dimensions. This indicates that a pointer
+ size storage model may be more consistent for the 1D case.
While multi-parameter operator[] would be something to wish for here,
it is by no means required for the implementation of multi
dimensional VLAs.
It is also possible to define semi-Variable array members like this:
int x[][4]; // x is a variadic array of arrays of four ints.
The other order:
int x[4][];
is also possible.
The constructor syntax should probably be to write [] for the fixed
dimensions so that if you superimpose the ctor and the declaration
each dimension has exactly one expression. This way everyone "knows"
which dimensions are variable without seeing the constructor bodies.
Non-rectangular VLAs
--------------------
Non rectangular VLAs would require that each of the minor rank arrays
can somehow get a different size. This can be exemplified like this:
int major = 10;
int vla[major][rand()%10];
While such a construct is perhaps useful sometimes it also allows
other more plausible uses, like this:
int major = 10; // Not const!
int sizes[major] = { ... }
size_t i = 0;
int data[major][sizes[i++]];
The problem here is that the compiler can't really know if the
programmer intended the minor size expression to be evaluated once or
10 times. It can also be very hard for the compiler to know if the
value is going to be the same for each of the minor arrays, and thus
to select storage layout.
To remedy this I suggest adding some syntax to make this clear:
int data[i: major][sizes[i]];
Here the variable i is introduced in a way akin to the range based
for, and can be used in subsequent array bounds expressions for the
same array. If this construct is NOT used each array bound expression
is evaluated only once creating a rectangular array. This gives the
compiler a chance to select a suitable indexing scheme.
This is also useful for vlas inside objects, like this:
class many_arrays {
many_arrays(int sizes[]) arrays[i : std::size(sizes)](sizes[i]) {}
bg_array arrays[];
};
Note: The example uses std::size asked for above and the array
element constructor feature suggested by others, which plays very
well with the array constructor loop variable.
Indeed array constructor loop variables can be used also when
initiating the values of a fixed size array, which would probably
look like this:
int x[i:5](i);
And in a class member case:
class fixed_array {
fixed_array() : x[i:](i) {}
int x[5];
};
The first example above also needs to be revised to:
int major = 10;
int vla[:major][rand()%10];
Here the colon is added before major just to indicate that the minor
bound expression needs to be evaluated for each major element with
an unnamed array constructor loop variable.
All of this should be quite easy to implement on the code generation
side given the three phase system described above, although of course
the memory need on stack could be higher than anticipated for a large
major axis bound: all the random numbers must be saved somewhere to
set up the array data structure properly after all the VLA elements
have been allocated into ONE block of memory!
A new STL container based on a VLA
----------------------------------
I think it could be worthwhile to consider adding a new container
similar to vector to the C++ standard. The difference from a vector
is that there is a maximum size which has to be set at constructor
time.
In contrast with a plain VLA or array<> this container does not
construct the elements immediately, it just contains a char[] VLA of
appropriate size and then uses the same mechanisms as vector to
actually create the contents (in place new, explicit destructor
calls) in push_back and insert etc.
The name of this could be bounded_vector or some other outcome of the
bikeshedding process.
As there will be just one VLA memory block I don't see any other
container that would benefit from a VLA based variant. Possibly
unordered_set/map where a hash table with a fixed number of bins
could be useful.
--
---
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_248_30244795.1402267946760
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>I think that the work towards allowing variable lengt=
h arrays in C++</div><div>is very important, as it reinforces the performan=
ce advantage of C++</div><div>over other languages. After all, the number o=
f memory allocations</div><div>have a large performance impact and the lack=
of VLAs is a major</div><div>reason for allocations in C++.</div><div><br>=
</div><div>The main problem with having VLAs in objects is how to calculate=
the</div><div>size before the object's memory is allocated. This is necess=
ary to be</div><div>able to keep a heap allocated object in one malloc bloc=
k.</div><div><br></div><div>The solution offered by N4025 lays a large burd=
en on both the</div><div>programmer and the compiler:</div><div><br></div><=
div>The programmer needs to annotate both the constructor parameters used</=
div><div>in the bounds expressions and the members used to store the bounds=
</div><div>after construction. Compilers need to calculate the bounds value=
</div><div>twice using different code, in the first phase to some stack var=
iable</div><div>that represents the bounds member and then again to actuall=
y set up</div><div>its value in phase 2. There are also a plethora of error=
conditions</div><div>that the compiler needs to check for, such as program=
mers forgetting</div><div>to annotate parameters or members or make them no=
n-const.</div><div><br></div><div>My proposal gets rid of this hazzle by le=
aving the constructor</div><div>parameters on the stack between the phases.=
While this may seem scary</div><div>at first, after looking at it in detai=
l I find it quite reasonable. A</div><div>lot of the results of my investig=
ation are presented below.</div><div><br></div><div>My design goals were a =
little different than those of N4025:</div><div><br></div><div>I didn't wan=
t to add special syntax for bound expressions</div><div>or bound-expression=
-participating members. Instead I wanted the</div><div>intuitive syntax of =
putting the array bound initializing</div><div>expression in the constructo=
r initializer list, without forcing the</div><div>constructors to be inline=
.. Also I didn't allow the implementation to</div><div>evaluate the bounds e=
xpressions more than once.</div><div><br></div><div>To accomplish this I su=
ggest a multi phase construction system which</div><div>works like this:</d=
iv><div><br></div><div>0. Allocate space for the actual object to be constr=
ucted if it has</div><div>stack storage class.</div><div><br></div><div>1. =
Save the stack pointer. Probably in a register that</div><div>the calling c=
onvention requires to be saved.</div><div><br></div><div>2. Call the first =
phase constructor which evaluates all</div><div>constructor expressions for=
subobjects with VLAs and all VLA bounds</div><div>expressions and returns =
the total number of bytes required for all</div><div>VLA elements.</div><di=
v><br></div><div>3. Allocate memory for the object + VLA elements (heap</di=
v><div>case) or just the VLA elements (static and automatic cases). </=
div><div><br></div><div>4. Call the second phase constructor with three poi=
nters: The object</div><div>'this' pointer, the VLA memory start address an=
d the saved stack</div><div>pointer from step 1. The second phase construct=
or can find the</div><div>pre-calculated constructor parameters and VLA bou=
nds using the saved</div><div>stack pointer and sets up the object, pointin=
g the VLA pointers into the</div><div>allocated memory.</div><div><br></div=
><div>5.Call the third phase constructor which just destroys</div><div>all =
the values saved in phase 1. This phase is also used in case of a</div><div=
>constructor exception and in sizeof.(unevaluated context).</div><div><br><=
/div><div>One drawback of this system is that the order of evaluation of</d=
iv><div>constructor expressions is somewhat surprising: All constructor</di=
v><div>parameters for objects with VLAs are evaluated _before_ those of</di=
v><div>non-VLA subobjects. The strict LIFO order of construction/destructio=
n</div><div>is however kept, so in normal circumstances this should not be =
a</div><div>problem. Note that this does not affect objects without VLAs in=
them,</div><div>so there is no backwards compatiblity issue.</div><div><br=
></div><div>Another issue may be that this system basically requires VLA el=
ements</div><div>to be stored in a separate side stack and not in the norma=
l stack.</div><div>This is as otherwise the memory used for constructor par=
ameter values</div><div>would be "trapped" under the VLA elements on the st=
ack until the VLA</div><div>object is popped. While this need increases the=
complexity of the runtime</div><div>system it also has the advantage that =
the risk of stack overflow is</div><div>greatly reduced as the side stack c=
an easily be segmented. As the</div><div>basic idea with VLAs is to move he=
ap data to the stack the risk of</div><div>overflow is otherwise changed fr=
om too deep recursions to too large</div><div>data sets.</div><div><br></di=
v><div>Finally, as there is no object yet in phase 1 it can't be permitted<=
/div><div>to use non-static members in subobject constructor expressions fo=
r</div><div>subobjects with VLAs. This is bad practice anyway but is of cou=
rse</div><div>used today in some code. Again, as this limitation applies on=
ly to</div><div>subobjects with VLAs it is not a breaking change, but unfor=
tunate as</div><div>we must have different rules depending on whether the s=
ubobject has</div><div>VLAs or not. Also it can be quite hard for the compi=
ler to figure out</div><div>if member data is actually used unless it is al=
so forbidden to call</div><div>non-static methods.</div><div><br></div><div=
><br></div><div>Here is an example whoing the problem: two_arrays construct=
or mutates its</div><div>parameters.</div><div><br></div><div class=3D"pret=
typrint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-wo=
rd; background-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div=
class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> bg_array </span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
bg_array</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">size_t sz</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: #660;" class=3D"styled-by-prettify">:</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> m_data</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">[</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">sz</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: #660;" class=3D"styled-b=
y-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br> </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">for</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
size_t i </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #066;" class=3D"styled-by-prettify">0</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> i </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify"><</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> sz</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> i</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">++)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
> m_data</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">[</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify">i</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">]</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><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"styled-by-prettify"><br> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> m_data</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">[];</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br><br><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">struct</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> two_arrays </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br> two_arrays</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> sz1</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;" class=3D"styled-by-prettify">int</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> sz2</span><sp=
an 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=
: #660;" class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> first</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">(++</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">sz1</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">),</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> second</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
(++</span><span style=3D"color: #000;" class=3D"styled-by-prettify">sz2</sp=
an><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: #660;" class=3D"styled-by-prettify">{}</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"><br> bg_array first</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> second</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><br>two_arrays v</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #066;" =
class=3D"styled-by-prettify">10</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettif=
y">20</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></spa=
n></div></code></div><div><br><br></div><div>Here it is quite evident that =
it is not allowed to evaluate the</div><div>constructor parameters more tha=
n once, as the sz1 and sz2 would be</div><div>incremented twice, and the ar=
ray size would not be the same as the loop</div><div>count of the initiatio=
n!</div><div><br></div><div><br></div><div>The inside of a reference implem=
entation:</div><div>----------------------------------------</div><div><br>=
</div><div>Here is pseudo-code for the example above which I wrote to make =
sure this system could work.</div><div><br></div><div>The v construction ca=
ll site code is something like this (assuming v</div><div>is a static varia=
ble and sp is a pointer to the stack):</div><div class=3D"prettyprint" styl=
e=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; backgroun=
d-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"sub=
prettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
<br></span><span style=3D"color: #800;" class=3D"styled-by-prettify">// Obj=
ect memory reservation not needed as v is in static storage.</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br></span><span =
style=3D"color: #800;" class=3D"styled-by-prettify">// Setup constructor ar=
gument values as usual. These could be complex expressions of course.</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: #008;" class=3D"styled-by-prettify">reinterpret_cast</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">*>(</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify">sp</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
</span><span style=3D"color: #066;" class=3D"styled-by-prettify">10</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br>sp </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">+=3D</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">sizeof</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">int</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">*<=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">reinterpret=
_cast</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><<=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">*>(</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify">sp</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: #660;" =
class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"style=
d-by-prettify">20</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><b=
r>sp </span><span style=3D"color: #660;" class=3D"styled-by-prettify">+=3D<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">sizeof</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br><br><br></span><span style=3D"color: #800;" =
class=3D"styled-by-prettify">// Here the three phases of the constructor ar=
e called and the memory itself allocated. There will be just small variatio=
ns here</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
></span><span style=3D"color: #800;" class=3D"styled-by-prettify">// depend=
ing on the storage class:</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">char</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">*</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> tmpfp=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> sp</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: #8=
00;" class=3D"styled-by-prettify">// Save stack pointer after ctor paramete=
rs are pushed.</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br>size_t mem_size </span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> two_arrays</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
two_arrays_phase1</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">sp=
</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: #800;" class=3D"styled-by-prettify">// Calculate memory size an=
d save values on stack.</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">char</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>*</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> vdata <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> staticallocator</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">alloc</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">mem_size</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: #800;" class=3D=
"styled-by-prettify">// Get the memory required from the special static VLA=
data stack. __atexit code will free this memory (if needed)</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>two_arrays</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">two_arrays_phase2</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">sp</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">,</span><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"styl=
ed-by-prettify">v</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> v=
data</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> tmpfp</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #800;" class=3D"styled-by-prettify">// Perform the real construction at =
v, allocating VLAs from vdata, with tmpfp indicating where ctor expression =
values and array sizes are.</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>two_arrays</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">two_arrays_phase3</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify">sp</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">// Destroy cto=
r parameter values and get rid of array size values. Restore sp.</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br><br></spa=
n></div></code></div><div><br><br></div><div>The different phases of the tw=
o_arrays constructor:</div><div><br></div><div class=3D"prettyprint" style=
=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background=
-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subp=
rettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">size_=
t two_arrays_phase1</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #008;" class=3D"styled-by-prettify">=
char</span><span style=3D"color: #660;" class=3D"styled-by-prettify">*&=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> sp</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span sty=
le=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: #0=
00;" class=3D"styled-by-prettify"><br> </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"> fp </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> sp</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br><b=
r> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">//=
Evaluate constructor expressions for 'first' ctor</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br> </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">*</span><span style=3D"color: #008;=
" class=3D"styled-by-prettify">reinterpret_cast</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify"><</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify">size_t</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">*>(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">sp</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</span><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: #008;" class=3D"styled-by-prettify">reinterpret_cast</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">*>(</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">fp </span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">-</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"st=
yled-by-prettify">2</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </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;" class=3D"styled-by-prettify">sizeof</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">));</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"><br> sp </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">+=3D</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">sizeof</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">size_t</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br=
><br> </span><span style=3D"color: #800;" class=3D"styled-by-prettify"=
>// Call phase 1 for 'first'</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br> size_t ret </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> bg_array_phase1</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify">sp</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br> <br> </span><span style=3D"color: #800;" class=3D"style=
d-by-prettify">// Evaluate constructor expressions for 'second' ctor</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br> </span>=
<span style=3D"color: #800;" class=3D"styled-by-prettify">// NOTE: fp is ne=
cessary as we don't know how much bg_array_phase1 moves sp.</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br> </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">*</span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">reinterpret_cast</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify">size_t</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">*>(</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify">sp</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">=3D</span><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: #008;" class=3D"styled-by-prettify">reinterpret_cast=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">*>(</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">fp </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">-</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">sizeof</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by=
-prettify">int</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">));</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
> sp </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
+=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">sizeof</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">size_t</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"><br><br><br> </span><span style=3D"=
color: #800;" class=3D"styled-by-prettify">// Call phase 1 for 'second' and=
sum up the memory use.</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br> ret </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">+=3D</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> bg_array_phase1</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify">sp</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br>=
<br> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">=
// NOTE: No decrement of stack pointer!</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br><br><br> </span><span style=3D"color:=
#008;" class=3D"styled-by-prettify">return</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> ret</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br><br><br></span><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">void</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
two_arrays_phase2</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">(</span><span style=3D"color: #008;" class=3D"styled-by-prettify">ch=
ar</span><span style=3D"color: #660;" class=3D"styled-by-prettify">*</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> sp</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">char</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">object</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">char</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">*&</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> memoryblock</span><spa=
n 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;" class=3D"styled-by-prettify">char</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">*&</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> tmpfp</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">=
// Call phase two of members. Their code will affect memoryblock and =
tmpfp pointers but not sp.</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br> bg_array_phase2</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">sp</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">ob=
ject</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">+</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> offsetof</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify">two_arrays</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> first</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">),</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> memoryblock</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> tmpfp</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br> bg_array_phase2</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">sp</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;" class=3D"styled-by-prettify">object</span><spa=
n 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"> offsetof</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">two_arrays</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> second</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">),</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> memoryblock</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> tmpfp</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 sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br></span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">void</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> two_arrays_phase3</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">char</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">*&</span><span style=3D"color:=
#000;" class=3D"styled-by-prettify"> sp</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"style=
d-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br> bg_array_phase3</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">sp</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #800;" class=3D"styled-by-prettify">// destroy 's=
econd' ctor parameter</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br> bg_array_phase3</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">sp</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// destr=
oy 'first' ctor parameter</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br><br><br> </span><span style=3D"color: #800;" class=
=3D"styled-by-prettify">// Destroy my constructor expression values in reve=
rse order</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br> sp </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">-=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">sizeof</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br> </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">*</span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">reinterpret_cast</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify"><</span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">int</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">*>(</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify">sp</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">).~</span><span style=3D"color: #008;" class=3D"styled-by-prettify">i=
nt</span><span style=3D"color: #660;" class=3D"styled-by-prettify">();</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span>=
<span style=3D"color: #800;" class=3D"styled-by-prettify">// sz2</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br> sp </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">-=3D</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">sizeof</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">int</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> <br> </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">*</span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">reinterpret_cast</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify"><</span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">int</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>*>(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">sp<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">).~</span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">();</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #800;" class=3D"styled-by-prettify">// sz1</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><br><br></span></div></code></div><div><br>=
<br></div><div>The the bg_array code looks like this, assuming that a VLA i=
s represented by a begin and end pointer.</div><div><br></div><div class=3D=
"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: bre=
ak-word; background-color: rgb(250, 250, 250);"><code class=3D"prettyprint"=
><div class=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styled=
-by-prettify">size_t bg_array_phase1</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">char</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">*&</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> sp</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: #660;" class=3D"styled-by-prettify">{</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">char</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">*</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> fp </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> sp</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br><br><br> </span><span style=3D"color: #800;" class=3D"sty=
led-by-prettify">// Calculate the VLA size in bytes. This expression can be=
complex and is free to use the stack.</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br> </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">*</span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">reinterpret_cast</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify"><</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">size_t</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">*>(</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify">sp</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><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: #=
008;" class=3D"styled-by-prettify">reinterpret_cast</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify"><</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">size_t</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">*>(</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">fp </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;" class=3D"styled-by-prettify=
">sizeof</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">size_t</spa=
n><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: #660;" class=3D"styled-by-prettify">*</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">sizeof</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">int</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
> sp </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
+=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">sizeof</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">size_t</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"><br><br><br> </span><span style=3D"=
color: #800;" class=3D"styled-by-prettify">// Return the amount of memory n=
eeded.</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">retu=
rn</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">*</span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">reinterpret_cast</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">size_t</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">*>(</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">fp</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cl=
ass=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-b=
y-prettify"><br><br><br></span><span style=3D"color: #008;" class=3D"styled=
-by-prettify">void</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> bg_array_phase2</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">char</span><span style=3D"color: #660;" class=3D"styled-by-prettify">*=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> sp</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">char</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">*</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styl=
ed-by-prettify">object</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">char</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">*&</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> memoryblock</sp=
an><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;" class=3D"styled-by-prettify">char</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">*&</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> tmpfp</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: #800;" class=3D"styled-by=
-prettify">// tmpfp is the sp value from phase1</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: #800;" class=
=3D"styled-by-prettify">// Setup VLA members, assumed to be two pointers, t=
o begin and end.</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">*</span><span style=3D"color: #008;" class=3D"styled-by-prettify">rei=
nterpret_cast</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y"><</span><span style=3D"color: #008;" class=3D"styled-by-prettify">int=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">**>(</s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">object</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"col=
or: #000;" class=3D"styled-by-prettify"> offsetof</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify">bg_array</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> m_data</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">))</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">reinterpret_cast=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">*>(</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">memoryblock</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br> memoryblock </span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">+=3D</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">reinterpret_cast</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">size_t</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">*>(</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify">tmpfp</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pr=
ettify">// Add precalculated array size in bytes set in phase 1.</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br> </span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">*</span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">reinterpret_cast</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">**>(</span><span style=3D"color:=
#008;" class=3D"styled-by-prettify">object</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">+</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> offsetof</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">bg_array</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> m_dat=
a</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: #660;" class=3D"styled-by-prettify">+</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;"=
class=3D"styled-by-prettify">sizeof</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">int</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">*))</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
style=3D"color: #008;" class=3D"styled-by-prettify">reinterpret_cast</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span=
style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">*>(</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">memoryblock</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"><br><br><br> </span><span style=3D=
"color: #800;" class=3D"styled-by-prettify">// Implementation of the constr=
uctor body. The access of sz (the constructor parameter) is via the tmpfp p=
ointer. Any storage required to implement the loop</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br> </span><span styl=
e=3D"color: #800;" class=3D"styled-by-prettify">// is allocated at sp as us=
ual. The offset between the two is not known here!</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br> </span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">for</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">size_t i </span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">0<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> i </span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">*</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">reinterpret_cast</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify"><</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">size_t</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">*>(</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">tmpfp </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">sizeof=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">size_t</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">));</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> i</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">++)</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br> m_data</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">[</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify">i</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: #660;" class=3D"styled-by-prettify=
">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><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><br><br> </span><span s=
tyle=3D"color: #800;" class=3D"styled-by-prettify">// Increment tmpfp as sp=
was incremented in phase1.</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br> tmpfp </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">+=3D</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">sizeof</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">size=
_t</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><br>size_t bg_array_pha=
se3</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">char</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">*&</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> sp</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br> sp </span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">-=3D</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">sizeof</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">size_t<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #800;" class=3D"styled-by-prettify">// Pass the VLA size</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br> =
</span><span style=3D"color: #800;" class=3D"styled-by-prettify">// Destroy=
my ctor parameter.</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br> sp </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">-=3D</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">siz=
eof</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">size_t</span><sp=
an 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=
: #008;" class=3D"styled-by-prettify">reinterpret_cast</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">*>(</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">sp</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">).~</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">size_t</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">();</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br><b=
r></span></div></code></div><div><br><br></div><div>Sizeof decoration</div>=
<div>-----------------</div><div><br></div><div>While I don't like the extr=
a syntax required in N4025 it does have</div><div>some merit to be able to =
specify to the compiler how to store the</div><div>size information of a VL=
A, as it can improve performance or reduce</div><div>memory use somewhat.</=
div><div><br></div><div>My belief is however that this syntax should be opt=
ional so that</div><div>there is a fallback representation that the compile=
r uses when no</div><div>bounds expression is written. This representation =
is most likely a</div><div>two pointer begin/end notation as this has prove=
n to be the best for</div><div>vector (at least that's whats being used).</=
div><div><br></div><div>Personally I have not ever felt a desire for having=
the size of a</div><div>vector stored in any particular way, using begin/e=
nd or size() is</div><div>just fine and even if you are lazy enough to use =
index based loops</div><div>instead of iterator based loops the compiler is=
often smart enough to</div><div>eradicate the difference. My point is that=
the same indifference to</div><div>how the size is stored is probably goin=
g to be prevalent for VLAs</div><div>too, which makes the inclusion of the =
rather complicated sizeof</div><div>decoration and bounds expressions quest=
ionable.</div><div><br></div><div><br></div><div>Interpretation of sizeof</=
div><div>------------------------</div><div><br></div><div>It seems logical=
that sizeof() on classes containing VLAs include the</div><div>memory take=
n by these as there is a need for placement new to know</div><div>how much =
memory to allocate. The idea of using sizeof(Class(pars)) is</div><div>usef=
ul for this case, and it can be implemented by just calling phase</div><div=
>1 and 3 of the constructor without calling phase 2. This does not</div><di=
v>instantiate the type but evaluates the constructor expressions once,</div=
><div>as expected. (Less expected for nested objects with VLAs though, but<=
/div><div>necessary).</div><div><br></div><div>Doing sizeof on a preexistin=
g object with VLA(s) or on a VLA itself</div><div>should probably calculate=
the size in bytes based on the actual array</div><div>lengths. As this can=
be somewhat complicated it is reasonable that a</div><div>function to do t=
his is compiled as a separate entity for each class</div><div>with VLAs, so=
that the sizeof() can just make a simple function call.</div><div>Inlining=
this function is often reasonable and all the required</div><div>informati=
on to do so is available to the compiler as you need to have</div><div>seen=
the full class head to be able to do sizeof on an object anyway.</div><div=
>The usefulness of this operation is rather questionable, but not to</div><=
div>complicate the language specification with another special case it</div=
><div>should probably be allowed. A caveat to this idea is presented below<=
/div><div>when function paramters are discussed.</div><div><br></div><div>T=
his said there needs to be a way to determine the size of a VLA in</div><di=
v>elements. It is logical that the std::begin() and std:end() functions</di=
v><div>should be automagically overloaded for VLAs as the basis for this.</=
div><div>Then std::end(vla) - std::begin(vla) returns the size in elements =
and</div><div>range based for and stl algorithms work as expected.</div><di=
v><br></div><div>A free function could be added for general sizing use:</di=
v><div><br></div><div>template<typename T> size_t std::size(const T&a=
mp; obj) </div><div>{ </div><div> return std::end(ob=
j) - std::begin(obj);</div><div>}</div><div><br></div><div>To get the minim=
um size of an object of a class type with VLA you can</div><div>use sizeof(=
ClassName) to get the size without VLA data. Likewise you</div><div>can use=
sizeof(T[]) to get the size of the array "head" i.e. 2 *</div><div>s=
izeof(void*) or similar. NOTE: This could be a breaking change if</div><div=
>sizeof(T[]) is today specified to return the same as sizeof(T*). If</div><=
div>so the committe must decide which way to go. This is not so important</=
div><div>as it could also be specified that the size of a VLA "head" is the=
</div><div>same as two pointers in writing in the standard.</div><div><br><=
/div><div><br></div><div>Destroying objects with VLAs</div><div>-----------=
-----------------</div><div><br></div><div>Destroying objects with VLAs mus=
t take note of the storage class of</div><div>the object. This does not aff=
ect the destructor per se, as it never</div><div>deletes the memory used, o=
nly runs the destructors of the members</div><div>(including VLA elements).=
</div><div><br></div><div>It is instead the responsibility of the callsite =
to deallocate the</div><div>memory of the VLA elements as well as the objec=
t itself. For the heap</div><div>case this is likely done by just one free(=
) operation while on the</div><div>stack it would involve popping both the =
main and side stacks. To pop</div><div>the side stack by an appropriate amo=
unt the begin pointer of the</div><div>first VLA and/or the end pointer of =
the last VLA element must be</div><div>accessed.</div><div><br></div><div>N=
ote that it is very likely that the side stack can't be a pure LIFO</div><d=
iv>stack but it is probably good enough to have a used bit in each</div><di=
v>allocated block and then pop all trailing unused blocks, the locked</div>=
<div>in blocks are normally short lived. If VLA element blocks above a</div=
><div>certain treshold size are allocated directly on the heap such blocks<=
/div><div>don't get locked in so no really big unused holes in the side</di=
v><div>stack can occur.</div><div><br></div><div><br></div><div>Copying obj=
ects with VLAs</div><div>-------------------------</div><div><br></div><div=
>Following the convention of arrays in C++ objects in general copying</div>=
<div>of VLA members should be a deep copy. This means that the auto</div><d=
iv>generated copy constructor of a clas with a VLA must inspect the</div><d=
iv>incoming source object in phase 1 to find the sizes of its VLAs.</div><d=
iv><br></div><div>A user defined copy constructor must set up the sizes of =
the object's</div><div>VLA as any other constructor and typically would do =
this by checking</div><div>the source object.</div><div><br></div><div>I do=
n't remember if there is a suggestion to allow defering to the</div><div>de=
fault implementation for the copy construction and then "add some"</div><di=
v>but it would surely be of interest (this is a side track):</div><div><br>=
</div><div>MyClass::MyClass(const MyClass& src) : default(src) { -- do =
some checks on consistency for instance -- }</div><div><br></div><div><br><=
/div><div>Moving objects with VLAs</div><div>------------------------</div>=
<div><br></div><div>Moving objects with VLAs is only possible in special ci=
rcumstances. I</div><div>think that in general no move constructor or assig=
nment operator</div><div>should be auto-generated for classes with VLAs. Th=
ere are some</div><div>specific but useful cases where moving would be poss=
ible so there</div><div>should be writings that the compiler is allowed to =
elide the copying</div><div>of the object in certain situations such as fun=
ction returns. It then</div><div>becomes a quality of implementation issue =
when such elison is made by</div><div>a particular compiler.</div><div><br>=
</div><div>An example of why it is harder to reuse the VLA elements than on=
e may</div><div>think is presented below for the return case.</div><div><br=
></div><div><br></div><div>Returning VLAs and objects with VLAs</div><div>-=
-----------------------------------</div><div><br></div><div>An object retu=
rned from a function is eligible for moving to a</div><div>destination rath=
er than copying. For VLAs this moving presents a</div><div>unique problem a=
s there is an uncertainty on the storage class to use</div><div>for the VLA=
elements to make the move possible.</div><div><br></div><div>Returning a p=
lain VLA is probably not to be allowed as returning a</div><div>sized array=
is not allowed. If returning arrays is to become allowed</div><div>in the =
future the discussion below for objects containing VLAs can be</div><div>ex=
tended to this case.</div><div><br></div><div>Following the standard C++ co=
nventions the object returned is of</div><div>course on the stack, and thus=
its VLA elements should be on the side</div><div>stack. But can they be mo=
ved into the receiving object? This is far</div><div>from obvious, as can b=
e seen by the example below.</div><div><br></div><div class=3D"prettyprint"=
style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; back=
ground-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">struct</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
vla_class </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br> =
;vla_class</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
(</span><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> sz</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: #6=
60;" class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> vla</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">[</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">sz</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: #660;" class=3D"styled-by-prettify">{</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br> </span><span st=
yle=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> i</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br> </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">for</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-prettify"=
>auto</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> vla</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br> x <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> i</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">++;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br> </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br><br><br> </span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> vla</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">[];</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br><br><br><br><br>vla_class my_function</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> </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">return</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> vla_class</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">(</span><span style=3D"color: #066;" class=3D"styled-by-prettify=
">3</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br></span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">struct</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> outer </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"><br> outer</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify">vla_class v</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;" class=3D"style=
d-by-prettify">int</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> x</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: #660;" class=3D"styled-by-prettify">:</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> x</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">[</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify">x</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">],</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> vlav</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">v</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">{}</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br> </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">float</span><span style=3D"color:=
#000;" class=3D"styled-by-prettify"> x</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">[];</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br> vla_class vlac</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><br></span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">void</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> main</span><span style=3D"color: #660;" class=3D"style=
d-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; outer obj</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
my_function</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>(),</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #066;" class=3D"styled-by-prettify">3</span><span s=
tyle=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;" c=
lass=3D"styled-by-prettify"><br><br><br><br></span></div></code></div><div>=
<br><br></div><div>Now, following the three phase system the constructor ar=
guments for</div><div>outer::outer are first evaluated. This means that my_=
function gets</div><div>called already in phase 1 and returns the vla_class=
object which is</div><div>stored in the stack until phase 2. The phase 1 c=
tor for outer is then</div><div>called and finds that the vlac member is to=
be copy constructed so</div><div>can see its size. (BTW: Would this code e=
ven be allowed by N4025?).</div><div><br></div><div>It now seems possible t=
hat the VLA elements on the side stack could</div><div>be moved to the vlac=
member. The problem is when obj is ultimately</div><div>destroyed. At this=
time the x elements and VLA elements are not</div><div>contiguous in the s=
ide stack and need to be separately freed from it,</div><div>while in the n=
ormal case (for instance for an outer on the heap) only</div><div>one such =
free-up operation needs to be done. If the outer ctor phase</div><div>1 is =
in another module it can't know that the VLA elements of the</div><div>vla_=
class returned from my_function are available for elison, and</div><div>mus=
t thus request the full size memory block for all VLA elements.</div><div><=
br></div><div>At the same time there are plenty of cases where it is possib=
le to</div><div>move the elements (for instance if the x member of outer is=
removed</div><div>above) and constructors are inline. And also, by trackin=
g the</div><div>lifetime of the outer object the compiler can actually gene=
rate</div><div>special code to do the two free up operations for this parti=
cular</div><div>instance of outer, as this freeing is the responsibility of=
the call</div><div>site anyway.</div><div><br></div><div>Thus as for movin=
g in general it seems reasonable to allow compilers</div><div>to do this ty=
pe of optimization at will (return elision) just as for</div><div>other typ=
es of objects.</div><div><br></div><div><br></div><div>Passing VLAs as func=
tion parameters</div><div>-----------------------------------</div><div><br=
></div><div>My suggestion on this topic is that the function parameter type=
T x[]</div><div>which is today the same as T* is redefined to be different=
in that</div><div>both the begin and end of the actual parameter are passe=
d in to the</div><div>function. For backwards compatibility it must unfortu=
nately be</div><div>allowed to use a pointer as the actual parameter to suc=
h a formal but</div><div>in this case the pointer can be pushed twice (both=
as the begin and</div><div>end values). This means that for old functions =
(which obviously don't</div><div>do end() on the array parameter) work as a=
lways while new functions</div><div>interpret the pointer as an empty range=
.. A recompile will however be</div><div>necessary which could present some =
problems with dlls compiled with</div><div>different compiler versions. Var=
ious changes in library</div><div>implementation regularly breaks ABIs betw=
een compiler versions anyway</div><div>so I don't think this is a serious c=
oncern.</div><div><br></div><div>One source of breaking changes with this c=
ould be if user code uses</div><div>sizeof(x). Previously this always retur=
ned the size of a pointer</div><div>while now it will return the size in by=
tes of the entire array.</div><div>Remaining question is what the result of=
that sizeof can reasonably</div><div>have been used for... On the other ha=
nd, as begin() and end() work</div><div>for VLAs there is little need for a=
sizeof() so maybe it can still</div><div>return the size of a pointer!</di=
v><div><br></div><div>Due to this problem it is likely that VLA function pa=
rameters would</div><div>not be allowed in variable number function paramet=
er lists (...) as</div><div>the macros used to handle those rely on the siz=
eof being correct when</div><div>bumping the stack pointer.</div><div><br><=
/div><div>There is of course a slight performance penalty for this change,<=
/div><div>incurred also for old functions (the pushing of the end value) bu=
t I</div><div>think this is acceptable comparing to the big upside for new<=
/div><div>functions (and in case of trouble the old function can be changed=
to</div><div>take a T* instead).</div><div><br></div><div class=3D"prettyp=
rint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word;=
background-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div cl=
ass=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">void</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
my_func</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(<=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">[])</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br> </span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">for</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> i </span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">:</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br> &nb=
sp; cout </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
lt;<</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> i<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br><br></span></div></code></div><=
div><br><br></div><div>This now actually works as expected!</div><div><br><=
/div><div>There is the issue of what to do in a mismatch situation, i.e. wh=
en</div><div>calling a function that takes a fixed size array with a mismat=
ching</div><div>VLA. In this case, just as today, we just pass the begin po=
inter to</div><div>the function. No error. We can't know that it is an erro=
r to send in</div><div>a longer VLA to a function that wants a shorter, fix=
ed size, array.</div><div>We can't even know that sending in a too short ar=
ray is a problem,</div><div>the function maybe doesn't use all of its param=
eter...</div><div><br></div><div>Note that at least on VS2013 you can't do =
a range based for on a</div><div>fixed size array parameter as the compiler=
has forgotten the size. I</div><div>think that if range based for is fixed=
to work for variable size</div><div>array parameters it is reasonable to c=
hange the language so that it</div><div>is allowed for fixed size array par=
ameters too.</div><div><br></div><div><br></div><div>Array slices as VLA pa=
rameters</div><div>------------------------------</div><div><br></div><div>=
If we get the possibility to send a VLA to a function and use its</div><div=
>size inside it would of course be nice to be able to slice the array,</div=
><div>i.e. to offset its begin value and reduce its end value. With the</di=
v><div>suggestions so far presented this is not possible.</div><div><br></d=
iv><div>However, it would be feasible to allow casting of a VLA to another<=
/div><div>array type, including one with a runtime size. This goes also for=
a</div><div>fixed size array and a pointer:</div><div><br></div><div class=
=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: =
break-word; background-color: rgb(250, 250, 250);"><code class=3D"prettypri=
nt"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">int</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> sz </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </=
span><span style=3D"color: #066;" class=3D"styled-by-prettify">56</span><sp=
an 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"co=
lor: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> my_vla</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">[</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">sz</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">];</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">int</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> my_a=
rr</span><span style=3D"color: #660;" class=3D"styled-by-prettify">[</span>=
<span style=3D"color: #066;" class=3D"styled-by-prettify">56</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">];</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> my_ptr </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> my_arr</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br>vector</span><span style=3D"color: #080;" class=3D"styled-by-prettify">&=
lt;int></span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
my_vec</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br>=
</span><span style=3D"color: #800;" class=3D"styled-by-prettify">// Use sli=
ce from 10 to 20 based on these:</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br><br><br></span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> smallsz </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify=
">10</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>my_func</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">reinterpret_cast</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">[</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">smallsz</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">]>(</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify">my_vla </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">+</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-=
prettify">10</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">));</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">// Use array-&=
gt;pointer decay first.</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br>my_func</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">reinterpret_cast</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify"><</span><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">int</span><span style=3D"color: #660;" class=3D"styled-by-prettify">[<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">smallsz</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">]>(</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">my_arr </span><spa=
n 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=
: #066;" class=3D"styled-by-prettify">10</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: #800;" class=3D"style=
d-by-prettify">// Use array->pointer decay first.</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>my_func</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">reinterpret_cast</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify"><</span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">int</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">[</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">smallsz</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">]>(</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify">my_ptr </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">+</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #066;" class=3D"styled-by-prettify">10</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">));</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>my_func</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">reinterpret_cast</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">[</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">my_vec</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">size</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">()]>(</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">my_vec</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">data</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">()));</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br><br><=
/span></div></code></div><div><br><br></div><div>What's bizarre about this =
is of course the use of a non-const</div><div>expression inside the <>=
; of the reinterpret_cast. This is rather</div><div>counter-intuitive, but =
in line with the already suggested extension</div><div>of sizeof. It is pos=
sible that this should be allowed for static cast</div><div>too, and even d=
ynamic_cast<> could be reused to do this "safely" i.e.</div><div>to c=
heck that we are not increasing the size beyond the parameter's</div><div>s=
ize. I don't see how this could be differentiated between the</div><div>"th=
row" and "nullptr" results if such a cast fails though.</div><div><br></div=
><div><br></div><div>It could be better syntactically to introduce a new ma=
gic function in</div><div>std:</div><div class=3D"prettyprint" style=3D"bor=
der: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-color:=
rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettypr=
int"><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></sp=
an><span style=3D"color: #008;" class=3D"styled-by-prettify">template</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span=
style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> T</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: #660;" c=
lass=3D"styled-by-prettify">***</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify">T</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">[]***</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> slice</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">T</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">*</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> start</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> size_t size</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br> </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">...</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> something </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">...</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><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><br>=
<br></span></div></code></div><div><br><br></div><div>This is a magic funct=
ion as the return type is not a VLA by value</div><div>(it doesn't own the =
VLA elements), nor is it by reference as there is no</div><div>VLA pointer =
pair to refer to!</div><div><br></div><div>The copying logic for VLAs is al=
so the same as other arrays when in</div><div>objects, that is, they are co=
pied deeply. By wrapping a VLA into a</div><div>simple object value semanti=
cs can thus be achieved.</div><div><br></div><div><br></div><div>Exception =
unwinding</div><div>-------------------</div><div><br></div><div>Constructo=
r expression values are now stored on the stack between the</div><div>first=
and third phase of the construction. Exception unwinding during</div><div>=
construction has to take this into account, but this is rather easy.</div><=
div><br></div><div>Exceptions during phase 1 are unwound like for any set o=
f values</div><div>being pushed on the stack.</div><div><br></div><div>Exce=
ptions during memory allocation or phase 2 must make sure to</div><div>dest=
roy all the parameters by calling phase 3.</div><div><br></div><div>Excepti=
ons during phase 3 are destructor exceptions and thus basically UB.</div><d=
iv><br></div><div><br></div><div>Multidimensional VLAs</div><div>----------=
-----------</div><div><br></div><div>Rectangular VLAs of any number of dime=
nsions should not be any</div><div>problem to define. Without additional co=
mpiler support the</div><div>implementation will be an array of VLAs, i.e. =
pointer pairs. This is</div><div>less efficient and less space efficient th=
an need be. I think it</div><div>could be a quality of implementation issue=
if this basic layout is</div><div>used or if multidimensional VLAs get spe=
cial treatment to reduce the</div><div>overhead.</div><div><br></div><div>S=
uch a multidimensional VLA data structure will require more data</div><div>=
members, i.e. sizes for all dimensions. This indicates that a pointer</div>=
<div>+ size storage model may be more consistent for the 1D case.</div><div=
><br></div><div>While multi-parameter operator[] would be something to wish=
for here,</div><div>it is by no means required for the implementation of m=
ulti</div><div>dimensional VLAs.</div><div><br></div><div>It is also possib=
le to define semi-Variable array members like this:</div><div><br></div><di=
v>int x[][4]; // x is a variadic array of arrays of four ints.</div><=
div><br></div><div>The other order:</div><div><br></div><div>int x[4][];</d=
iv><div><br></div><div>is also possible.</div><div><br></div><div>The const=
ructor syntax should probably be to write [] for the fixed</div><div>dimens=
ions so that if you superimpose the ctor and the declaration</div><div>each=
dimension has exactly one expression. This way everyone "knows"</div><div>=
which dimensions are variable without seeing the constructor bodies.</div><=
div><br></div><div><br></div><div>Non-rectangular VLAs</div><div>----------=
----------</div><div><br></div><div>Non rectangular VLAs would require that=
each of the minor rank arrays</div><div>can somehow get a different size. =
This can be exemplified like this:</div><div><br></div><div>int major =3D 1=
0;</div><div>int vla[major][rand()%10];</div><div><br></div><div>While such=
a construct is perhaps useful sometimes it also allows</div><div>other mor=
e plausible uses, like this:</div><div><br></div><div class=3D"prettyprint"=
style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; back=
ground-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">int</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> maj=
or </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #066;" class=3D"styled-by-prettify">10</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: #800;" cla=
ss=3D"styled-by-prettify">// Not const!</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><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"> sizes</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">[</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">major</span><span style=3D"color: #660;" class=3D"styled-by-prettify">]=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">{</span><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"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br><br><br>size_t i </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">0</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> data</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">[</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">major</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">][</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">sizes</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">[</span><span style=3D"color: #000;" class=3D"styled-by-prettify">i=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">++]];</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br><br=
></span></div></code></div><div><br><br></div><div>The problem here is that=
the compiler can't really know if the</div><div>programmer intended the mi=
nor size expression to be evaluated once or</div><div>10 times. It can also=
be very hard for the compiler to know if the</div><div>value is going to b=
e the same for each of the minor arrays, and thus</div><div>to select stora=
ge layout.</div><div><br></div><div>To remedy this I suggest adding some sy=
ntax to make this clear:</div><div><br></div><div>int data[i: major][sizes[=
i]];</div><div><br></div><div>Here the variable i is introduced in a way ak=
in to the range based</div><div>for, and can be used in subsequent array bo=
unds expressions for the</div><div>same array. If this construct is NOT use=
d each array bound expression</div><div>is evaluated only once creating a r=
ectangular array. This gives the</div><div>compiler a chance to select a su=
itable indexing scheme.</div><div><br></div><div>This is also useful for vl=
as inside objects, like this:</div><div><br></div><div class=3D"prettyprint=
" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; bac=
kground-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">class</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> m=
any_arrays </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;many_arrays</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">(</span><span style=3D"color: #008;" class=3D"styled-by-prettify">int</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> sizes</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">[])</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> arrays</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">[</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">i </span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">size</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">sizes=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)](</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">sizes</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">[</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">i</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">])</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">{}</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br><br><br> bg_array arrays</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">[];</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br><br><br><br></span></div></code></div><div><br>Note=
: The example uses std::size asked for above and the array</div><div>elemen=
t constructor feature suggested by others, which plays very</div><div>well =
with the array constructor loop variable.</div><div><br></div><div>Indeed a=
rray constructor loop variables can be used also when</div><div>initiating =
the values of a fixed size array, which would probably</div><div>look like =
this:</div><div><br></div><div><br></div><div class=3D"prettyprint" style=
=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background=
-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subp=
rettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">int</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">[</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">i</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">:</span><span style=3D"color: #066;" =
class=3D"styled-by-prettify">5</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">](</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">i</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><=
br><br><br><br></span><span style=3D"color: #606;" class=3D"styled-by-prett=
ify">And</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">in</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> a </span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">class</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> member </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">case</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br><br><br></span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">class</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> fixed_array </span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br> fixed_array</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: #660;" class=3D"styled-b=
y-prettify">:</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> x</span><span style=3D"color: #660;" class=3D"styled-by-prettify">[</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify">i</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">:](</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">i</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: #660;" class=3D"=
styled-by-prettify">{}</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br><br><br> </span><span style=3D"color: #008;" c=
lass=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> x</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">[</span><span style=3D"color: #066;" class=3D"styled-by-pretti=
fy">5</span><span style=3D"color: #660;" class=3D"styled-by-prettify">];</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">};</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br></span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code><=
/div><div><br><br></div><div>The first example above also needs to be revis=
ed to:</div><div><br></div><div>int major =3D 10;</div><div>int vla[:major]=
[rand()%10];</div><div><br></div><div>Here the colon is added before major =
just to indicate that the minor</div><div>bound expression needs to be eval=
uated for each major element with</div><div>an unnamed array constructor lo=
op variable.</div><div><br></div><div>All of this should be quite easy to i=
mplement on the code generation</div><div>side given the three phase system=
described above, although of course</div><div>the memory need on stack cou=
ld be higher than anticipated for a large</div><div>major axis bound: all t=
he random numbers must be saved somewhere to</div><div>set up the array dat=
a structure properly after all the VLA elements</div><div>have been allocat=
ed into ONE block of memory!</div><div><br></div><div><br></div><div>A new =
STL container based on a VLA</div><div>----------------------------------</=
div><div><br></div><div>I think it could be worthwhile to consider adding a=
new container</div><div>similar to vector to the C++ standard. The differe=
nce from a vector</div><div>is that there is a maximum size which has to be=
set at constructor</div><div>time.</div><div><br></div><div>In contrast wi=
th a plain VLA or array<> this container does not</div><div>construct=
the elements immediately, it just contains a char[] VLA of</div><div>appro=
priate size and then uses the same mechanisms as vector to</div><div>actual=
ly create the contents (in place new, explicit destructor</div><div>calls) =
in push_back and insert etc.</div><div><br></div><div>The name of this coul=
d be bounded_vector or some other outcome of the</div><div>bikeshedding pro=
cess.</div><div><br></div><div>As there will be just one VLA memory block I=
don't see any other</div><div>container that would benefit from a VLA base=
d variant. Possibly</div><div>unordered_set/map where a hash table with a f=
ixed number of bins</div><div>could be useful.</div><div><br></div><div><br=
></div><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"><div><=
div class=3D"gmail_quote">
</div></div></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_248_30244795.1402267946760--
.
Author: Giovanni Piero Deretta <gpderetta@gmail.com>
Date: Mon, 9 Jun 2014 07:56:41 -0700 (PDT)
Raw View
------=_Part_381_32127602.1402325802037
Content-Type: text/plain; charset=UTF-8
Hi Richiard,
thanks for your reply and clarifications. just a couple of notes:
On Monday, June 2, 2014 7:53:13 PM UTC+1, Richard Smith wrote:
>
> On Mon, Jun 2, 2014 at 9:06 AM, Giovanni Piero Deretta <gpde...@gmail.com
> <javascript:>> wrote:
>
>>
>> [...]
>> I'm not really sold on the syntax, in particular I think that the
>> runtime evaluated sizeof() might not fly with the many in the
>> committee, but I'll leave the bike-shedding to others.
>>
>
> The runtime sizeof concern is a great point, and one which we spent some
> time agonizing over.
>
> There are two different flavours of objection to runtime-evaluated sizeof:
>
> * sizeof(expr) is no longer always a constant expression
> * sizeof(expr) might have side-effects, and might evaluate its operand.
>
> Our paper admits defeat on the first of these, but we believe we can
> address the second objection.
>
>
what about disallowing sizeof at all? (i.e. sort-of-considering the class
> as incomplete, maybe add a "partially complete" state. Instead add an
> additionall std::size_of() builtin that will return the size of an object
> at runtime?
>
>
> I also would like to see a discussion of how return of variable sizes
>> can be implemented and if and how arrays of variable sized types can
>> be supported (sizeof could potentially become O(n)).
>>
>
> These are both interesting issues, and are important to the composability
> of this feature.
>
> Returning objects of runtime size can be supported in principle (for
> instance, the caller can provide a fixed-size buffer, and the callee can
> use heap allocation if the buffer is insufficient; after the call, the
> caller can check the size of the returned object and shrink its buffer or
> detect that it needs to free the object). A future version of the paper
> will need to cover this, if the committee is in favor of pursuing the
> direction of this paper.
>
I did some reasearch and it seems that Ada has language support for stack
allocated runtime sized types. In particular returning them is allowed.
This is usually implemented via either a secondary stack or something
called Depressed Stack Pointer.
The first option is obvious, it is doable in C++, but the additional stack
is a big departure from the original C runtime
with the second option, the stack space for the return object is allocated
by the callee; this is tricky to do in c++ as by-value on stack arguments
need to be destroyed *after* the return object is constructed: preserving
this ordering will leave an hard to reuse hole in the stack where the
arguments were placed; I have the feeling that this could lead to blowing
the stack, but I can't imagine a scenario that would cause this. The only
two other solutions that I can think is either allow the compiler to delay
the construction of the return object (big and subtle language change), or
permit (but not require) an additional (epxensive) copy/move of the
returned object so that the compiler can compact the stack.
>
> Section 6.9 has our very brief response to arrays of runtime-sized types.
> We think hiding too much runtime cost behind built-in array indexing
> notation would be a disservice to programmers (in particular, arr[i] would
> be O(i) if 'arr' is an array of a runtime-sized type that is laid out in
> memory like a normal array). However, there's no real problem with
> multidimensional arrays of runtime bound as members of a runtime-sized
> class.
>
Maybe arrays of runtime sized objects should be allowed only if all objects
have the same size (checked at runtime, std::terminate called otherwise).
HTH,
-- gpd
--
---
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_381_32127602.1402325802037
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>Hi Richiard, <br><br>thanks for your reply and cla=
rifications. just a couple of notes:<br><br>On Monday, June 2, 2014 7:53:13=
PM UTC+1, Richard Smith wrote:<blockquote class=3D"gmail_quote" style=3D"m=
argin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"=
><div dir=3D"ltr"><div><div class=3D"gmail_quote">On Mon, Jun 2, 2014 at 9:=
06 AM, Giovanni Piero Deretta <span dir=3D"ltr"><<a href=3D"javascript:"=
target=3D"_blank" gdf-obfuscated-mailto=3D"pfONy7Zyk2oJ" onmousedown=3D"th=
is.href=3D'javascript:';return true;" onclick=3D"this.href=3D'javascript:';=
return true;">gpde...@gmail.com</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr"><br>[...]<br>I'm not really=
sold on the syntax, in particular I think that the<br>runtime evaluated si=
zeof() might not fly with the many in the<br>committee, but I'll leave the =
bike-shedding to others.</div></blockquote><div>
<br></div><div>The runtime sizeof concern is a great point, and one which w=
e spent some time agonizing over.</div><div><br></div><div>There are two di=
fferent flavours of objection to runtime-evaluated sizeof:</div><div><br>
</div><div> * sizeof(expr) is no longer always a constant expression</=
div><div> * sizeof(expr) might have side-effects, and might evaluate i=
ts operand.</div><div><br></div><div>Our paper admits defeat on the first o=
f these, but we believe we can address the second objection.</div>
<div><br></div></div></div></div></blockquote><div><br><br></div><blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div class=3D"gmai=
l_quote">what about disallowing sizeof at all? (i.e. sort-of-considering th=
e=20
class as incomplete, maybe add a "partially complete" state. Instead add
an additionall std::size_of() builtin that will return the size of an=20
object at runtime? <br><br><div><br></div><blockquote class=3D"gmail_quote"=
style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><d=
iv dir=3D"ltr">I also would like to see a discussion of how return of varia=
ble sizes<br>can be implemented and if and how arrays of variable sized typ=
es can<br>
be supported (sizeof could potentially become O(n)).</div></blockquote><div=
><br></div><div>These are both interesting issues, and are important to the=
composability of this feature.</div><div><br></div><div>Returning objects =
of runtime size can be supported in principle (for instance, the caller can=
provide a fixed-size buffer, and the callee can use heap allocation if the=
buffer is insufficient; after the call, the caller can check the size of t=
he returned object and shrink its buffer or detect that it needs to free th=
e object). A future version of the paper will need to cover this, if the co=
mmittee is in favor of pursuing the direction of this paper.</div></div></d=
iv></div></blockquote><div><br>I did some reasearch and it seems that Ada h=
as language support for stack allocated runtime sized types. In parti=
cular returning them is allowed. This is usually implemented via either a s=
econdary stack or something called Depressed Stack Pointer. <br><br>The fir=
st option is obvious, it is doable in C++, but the additional stack is a bi=
g departure from the original C runtime <br><br>with the second option, the=
stack space for the return object is allocated by the callee; this i=
s tricky to do in c++ as by-value on stack arguments need to be destroyed *=
after* the return object is constructed: preserving this ordering will leav=
e an hard to reuse hole in the stack where the arguments were placed; I hav=
e the feeling that this could lead to blowing the stack, but I can't imagin=
e a scenario that would cause this. The only two other solutions that I can=
think is either allow the compiler to delay the construction of the return=
object (big and subtle language change), or permit (but not require) an ad=
ditional (epxensive) copy/move of the returned object so that the compiler =
can compact the stack. <br> </div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div dir=3D"ltr"><div><div class=3D"gmail_quote">
<div><br></div><div>Section 6.9 has our very brief response to arrays of ru=
ntime-sized types. We think hiding too much runtime cost behind built-in ar=
ray indexing notation would be a disservice to programmers (in particular, =
arr[i] would be O(i) if 'arr' is an array of a runtime-sized type that is l=
aid out in memory like a normal array). However, there's no real problem wi=
th multidimensional arrays of runtime bound as members of a runtime-sized c=
lass.</div></div></div></div></blockquote><div><br>Maybe arrays of runtime =
sized objects should be allowed only if all objects have the same size (che=
cked at runtime, std::terminate called otherwise).<br><br>HTH,<br><br>-- gp=
d<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_381_32127602.1402325802037--
.
Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Wed, 11 Jun 2014 23:04:58 -0700 (PDT)
Raw View
------=_Part_723_7462593.1402553098182
Content-Type: text/plain; charset=UTF-8
>
>
>>
>> The runtime sizeof concern is a great point, and one which we spent some
>> time agonizing over.
>>
>> There are two different flavours of objection to runtime-evaluated sizeof:
>>
>> * sizeof(expr) is no longer always a constant expression
>> * sizeof(expr) might have side-effects, and might evaluate its operand.
>>
>> Our paper admits defeat on the first of these, but we believe we can
>> address the second objection.
>>
>>
>
> what about disallowing sizeof at all? (i.e. sort-of-considering the class
>> as incomplete, maybe add a "partially complete" state. Instead add an
>> additionall std::size_of() builtin that will return the size of an object
>> at runtime?
>>
>>
> I also would like to see a discussion of how return of variable sizes
>>> can be implemented and if and how arrays of variable sized types can
>>> be supported (sizeof could potentially become O(n)).
>>>
>>
>> These are both interesting issues, and are important to the composability
>> of this feature.
>>
>> Returning objects of runtime size can be supported in principle (for
>> instance, the caller can provide a fixed-size buffer, and the callee can
>> use heap allocation if the buffer is insufficient; after the call, the
>> caller can check the size of the returned object and shrink its buffer or
>> detect that it needs to free the object). A future version of the paper
>> will need to cover this, if the committee is in favor of pursuing the
>> direction of this paper.
>>
>
> I did some reasearch and it seems that Ada has language support for stack
> allocated runtime sized types. In particular returning them is allowed.
> This is usually implemented via either a secondary stack or something
> called Depressed Stack Pointer.
>
> The first option is obvious, it is doable in C++, but the additional stack
> is a big departure from the original C runtime
>
> with the second option, the stack space for the return object is
> allocated by the callee; this is tricky to do in c++ as by-value on stack
> arguments need to be destroyed *after* the return object is constructed:
> preserving this ordering will leave an hard to reuse hole in the stack
> where the arguments were placed; I have the feeling that this could lead to
> blowing the stack, but I can't imagine a scenario that would cause this.
> The only two other solutions that I can think is either allow the compiler
> to delay the construction of the return object (big and subtle language
> change), or permit (but not require) an additional (epxensive) copy/move of
> the returned object so that the compiler can compact the stack.
>
I think it could be allowed to let the callee destroy the function
arguments at will for functions returning objects with TLAs in them. As
there are no such objects today there can't be any such functions and thus
no breakng changes. It does however complicate the code generation as the
calling convention is now different. However, I'm not certain that this
does the trick in all cases, for instance when the callee defers the
construction of the return value to yet another function level, at least
not if we want to elide any copying on the way out.
>
>
>>
>> Section 6.9 has our very brief response to arrays of runtime-sized types.
>> We think hiding too much runtime cost behind built-in array indexing
>> notation would be a disservice to programmers (in particular, arr[i] would
>> be O(i) if 'arr' is an array of a runtime-sized type that is laid out in
>> memory like a normal array). However, there's no real problem with
>> multidimensional arrays of runtime bound as members of a runtime-sized
>> class.
>>
> My previous response solves this dilemma by not mandating that the TLA
elements are stored immediately following the "main object" but only
"somewhere else". This would be the case always for a secondary stack
approach, and becomes necessary anyway as soon as you try to nest objects
with TLAs in other object with members after the TLA enabled member. With
this thinking in place the array proper contains only the "main body" of
each element of the outer array and is thus indexable just as any array.
The thinking that the array elements are stored in addresses consequtive
with the main object I think relates to the old C struct tail idea where
you can have ONE variable length array in an object if a) it is the last
member, and b) you are very careful with your memory allocation. The good
thing about this is that you don't need to store a pointer to the start of
the data, you just index the array out of bounds. However, this approach
fails when you have multiple TLAs in one object. Ok, the compiler can still
make one of them "pointerless", for instance the first one. But this
seriously limits the usefulness of the entire TLA idea as now you can't use
this type as a member of a surrounding class: Its next member clashes with
the TLA array elements of the inner class.
To me it was thus quite obvious that ALL tlas in objects need a pointer to
the first element of the actual array data, and this does open up the
possibility for arrays of different length TLAs or objects with different
length TLAs.
My ojective with participating in this debate was to see how far we can
take the generality of TLAs and objects with TLAs. This is because I would
loathe a feature that is only useful sometimes, like "you can have a TLA in
an object, but only one" or "you can't return an object with TLAs from a
function". This is a high aspirtation but I think my previous post shows
that we can get further than at least I thought possible.
I am however concerned about vectors and similar containers. A vector of
objects with TLAs should "work" according to my "general use" idea, but
where does it allocate the TLA elements? I believe that this needs to be a
specialization of vector, which may be fine given the right support to be
able to implement it, but this will also mean that custom-made containers
will NOT be able to "work" without specialization. I will come back to this
in a later post, I'm running out of time now.
>
> Maybe arrays of runtime sized objects should be allowed only if all
> objects have the same size (checked at runtime, std::terminate called
> otherwise).
>
> HTH,
>
> -- gpd
>
>
--
---
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_723_7462593.1402553098182
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;b=
order-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D"=
gmail_quote"><br><div>
<br></div><div>The runtime sizeof concern is a great point, and one which w=
e spent some time agonizing over.</div><div><br></div><div>There are two di=
fferent flavours of objection to runtime-evaluated sizeof:</div><div><br>
</div><div> * sizeof(expr) is no longer always a constant expression</=
div><div> * sizeof(expr) might have side-effects, and might evaluate i=
ts operand.</div><div><br></div><div>Our paper admits defeat on the first o=
f these, but we believe we can address the second objection.</div>
<div><br></div></div></div></blockquote><div><br><br></div><blockquote clas=
s=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc =
solid;padding-left:1ex"><div dir=3D"ltr"><div><div class=3D"gmail_quote">wh=
at about disallowing sizeof at all? (i.e. sort-of-considering the=20
class as incomplete, maybe add a "partially complete" state. Instead add
an additionall std::size_of() builtin that will return the size of an=20
object at runtime? <br><div><br></div></div></div></div></blockquote></div>=
</blockquote><div><br></div><div><br></div><div> </div><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"><blockquote class=3D"gmail_q=
uote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddin=
g-left:1ex"><div dir=3D"ltr"><div><div class=3D"gmail_quote"><div></div><bl=
ockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #=
ccc solid;padding-left:1ex"><div dir=3D"ltr">I also would like to see a dis=
cussion of how return of variable sizes<br>can be implemented and if and ho=
w arrays of variable sized types can<br>
be supported (sizeof could potentially become O(n)).</div></blockquote><div=
><br></div><div>These are both interesting issues, and are important to the=
composability of this feature.</div><div><br></div><div>Returning objects =
of runtime size can be supported in principle (for instance, the caller can=
provide a fixed-size buffer, and the callee can use heap allocation if the=
buffer is insufficient; after the call, the caller can check the size of t=
he returned object and shrink its buffer or detect that it needs to free th=
e object). A future version of the paper will need to cover this, if the co=
mmittee is in favor of pursuing the direction of this paper.</div></div></d=
iv></div></blockquote><div><br>I did some reasearch and it seems that Ada h=
as language support for stack allocated runtime sized types. In parti=
cular returning them is allowed. This is usually implemented via either a s=
econdary stack or something called Depressed Stack Pointer. <br><br>The fir=
st option is obvious, it is doable in C++, but the additional stack is a bi=
g departure from the original C runtime <br><br>with the second option, the=
stack space for the return object is allocated by the callee; this i=
s tricky to do in c++ as by-value on stack arguments need to be destroyed *=
after* the return object is constructed: preserving this ordering will leav=
e an hard to reuse hole in the stack where the arguments were placed; I hav=
e the feeling that this could lead to blowing the stack, but I can't imagin=
e a scenario that would cause this. The only two other solutions that I can=
think is either allow the compiler to delay the construction of the return=
object (big and subtle language change), or permit (but not require) an ad=
ditional (epxensive) copy/move of the returned object so that the compiler =
can compact the stack. <br></div></div></blockquote><div><br></div><div>I t=
hink it could be allowed to let the callee destroy the function arguments a=
t will for functions returning objects with TLAs in them. As there are no s=
uch objects today there can't be any such functions and thus no breakng cha=
nges. It does however complicate the code generation as the calling convent=
ion is now different. However, I'm not certain that this does the trick in =
all cases, for instance when the callee defers the construction of the retu=
rn value to yet another function level, at least not if we want to elide an=
y copying on the way out.</div><div> </div><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;"><div dir=3D"ltr"><div> </div><blockquote class=3D"gm=
ail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;p=
adding-left:1ex"><div dir=3D"ltr"><div><div class=3D"gmail_quote">
<div><br></div><div>Section 6.9 has our very brief response to arrays of ru=
ntime-sized types. We think hiding too much runtime cost behind built-in ar=
ray indexing notation would be a disservice to programmers (in particular, =
arr[i] would be O(i) if 'arr' is an array of a runtime-sized type that is l=
aid out in memory like a normal array). However, there's no real problem wi=
th multidimensional arrays of runtime bound as members of a runtime-sized c=
lass.</div></div></div></div></blockquote></div></blockquote><div>My previo=
us response solves this dilemma by not mandating that the TLA elements are =
stored immediately following the "main object" but only "somewhere else". T=
his would be the case always for a secondary stack approach, and becomes ne=
cessary anyway as soon as you try to nest objects with TLAs in other object=
with members after the TLA enabled member. With this thinking in place the=
array proper contains only the "main body" of each element of the outer ar=
ray and is thus indexable just as any array.</div><div><br></div><div>The t=
hinking that the array elements are stored in addresses consequtive with th=
e main object I think relates to the old C struct tail idea where you can h=
ave ONE variable length array in an object if a) it is the last member, and=
b) you are very careful with your memory allocation. The good thing about =
this is that you don't need to store a pointer to the start of the data, yo=
u just index the array out of bounds. However, this approach fails when you=
have multiple TLAs in one object. Ok, the compiler can still make one of t=
hem "pointerless", for instance the first one. But this seriously limits th=
e usefulness of the entire TLA idea as now you can't use this type as a mem=
ber of a surrounding class: Its next member clashes with the TLA array elem=
ents of the inner class.</div><div><br></div><div>To me it was thus quite o=
bvious that ALL tlas in objects need a pointer to the first element of the =
actual array data, and this does open up the possibility for arrays of diff=
erent length TLAs or objects with different length TLAs.</div><div><br></di=
v><div>My ojective with participating in this debate was to see how far we =
can take the generality of TLAs and objects with TLAs. This is because I wo=
uld loathe a feature that is only useful sometimes, like "you can have a TL=
A in an object, but only one" or "you can't return an object with TLAs from=
a function". This is a high aspirtation but I think my previous post shows=
that we can get further than at least I thought possible.</div><div><br></=
div><div>I am however concerned about vectors and similar containers. A vec=
tor of objects with TLAs should "work" according to my "general use" idea, =
but where does it allocate the TLA elements? I believe that this needs to b=
e a specialization of vector, which may be fine given the right support to =
be able to implement it, but this will also mean that custom-made container=
s will NOT be able to "work" without specialization. I will come back to th=
is in a later post, I'm running out of time now.</div><div><br></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 dir=3D"ltr"><d=
iv><br>Maybe arrays of runtime sized objects should be allowed only if all =
objects have the same size (checked at runtime, std::terminate called other=
wise).<br><br>HTH,<br><br>-- gpd<br> </div></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_723_7462593.1402553098182--
.
Author: Lawrence Crowl <Lawrence@Crowl.org>
Date: Mon, 16 Jun 2014 21:20:27 -0700
Raw View
Overall, I think the approach is pretty sound so far.
What is the effect of changing a class implementation from not having a
run-time size to one having a run-time size?
Does adding the sizeof parameter affect the ABI?
If it does, then some classes cannot migrate.
If it does not, then existing ABIs are probably inadequate.
Does adding a run-time sized element in a derived class imply
modifying the base class?
If it does, then some classes cannot migrate.
If it does not, then I think there may be an implicit requirement
to infer sizeof variables.
Have you outlined an ABI that you think works?
Minor issues:
Specifying order of initialization by order of member address is not
quite technically correct.
You should probably be referencing N3899. In particular, it suggests
the possibility of disallowing non-nested allocation.
--
Lawrence Crowl
--
---
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/.
.