Topic: is_relocatable type trait


Author: Andrey Davydov <andrey.a.davydov@gmail.com>
Date: Tue, 28 Mar 2017 00:33:54 -0700 (PDT)
Raw View
------=_Part_2621_396928494.1490686434939
Content-Type: multipart/alternative;
 boundary="----=_Part_2622_1336553240.1490686434940"

------=_Part_2622_1336553240.1490686434940
Content-Type: text/plain; charset=UTF-8

Introduction
I'd like to raise the issue of the *relocatable *types one more time. It is
well known concept used under different names in the following libraries:
Folly (IsRelocatable), BDE (IsBitwiseMoveable), EASTL
(has_trivial_relocate), Qt (Q_MOVABLE_TYPE).
It is natural generalization of the *trivially copyable *types concept
which can be used for the optimization of objects relocation.

Motivation
Let's consider how the operation of std::vector content relocation can be
implemented for some complex user defined type T:
template<typename T>
void relocate(T* new_buffer, T* old_buffer, size_t size)
{
  for (size_t i = 0; i != size; ++i)
    new (new_buffer[i]) T(std::move_if_noexcept(old_buffer[i]));

  for (size_t i = 0; i != size; ++i)
    old_buffer[i].~T();
}
On the other side for trivially copyable types this operation reduces to
std::memcpy(new_buffer, old_buffer, size * sizeof(T)). Let's call the type
T *relocatable *if two consequtive calls
new(new_place) T(std::move(old_place));
old_place.~T();
can be replaced by memcpy(&new_place, &old_place, sizeof(T)). Of course,
all trivially copyable types are *relocatable *by definition. Let's
enumerate some relocatable types from the standard library.

   - shared_ptr: move constructor of the shared_ptr and destructor of the
   empty shared_ptr don't change shared count.
   - unique_ptr<T, D>, if D is relocatable (std::default_delete is
   trivially copyable therefore it is relocatable).
   - string and containers (at least when std::allocator is used).
   - optional<T>, variant<Ts...>, if T and Ts... are relocatable.

At least following operations from the standard library can be optimized
for relocatable types:

   - resize of vector,
   - resize of deque,
   - swap of the empty and non-empty optionals,
   - swap of the variants with the different current indices.

Also it is possible to specialize std::swap for relocatable types and
consequently a little optimize some of standard algorithms: *sort*,
inplace_merge, partition, unique, rotate, remove*, ...
template<typename T>
enable_if_t<is_relocatable_v<T>> swap(T& x, T& y)
{
  constexpr auto size = sizeof(T);
  aligned_storage_t<size> tmp;
  memcpy(&tmp, &x,   size);
  memcpy(&x,   &y,   size);
  memcpy(&y,   &tmp, size);
}

Yet another possible usage of the concept of relocatable type is extension
of copy ellision. Let's consider following code fragment:
vector<int> foo(bool c)
{
  vector<int> xs = { 1, 2, 3 }, ys = { 4, 5, 6 };
  if (c)
    return xs;
  else
    return ys;
}

auto result = foo(rand());
copy ellision doesn't work here, and so `result` will be move constructed,
but, in principle, return value of `foo` can be relocated to `result`.

Proposed language changes

   - Define *relocatable types* in [basic.types] p9 after *trivially
   copyable types.*

*... *are collectively called *trivially copyable types*. Trivially
copyable types, relocatable classes, arrays of such types and cv-qualified
versions of these types are collectively called *relocable types*.

   - Define *relocatable class *in [class] after *trivially copyable class.*

A class s is a *relocatable class* if it either explicitly marked as
relocatable or

   1. all basic classes are relocatable,
   2. all non-static data members are relocatable,
   3. s has a non-virtual, non-deleted and non user-defined destructor.

It should be discussed how to explicitly mark a class as relocatable. One
of the possible solutions is to allow specializations of the type trait
std::is_relocatable. For example,
template<typename T, typename D>
struct is_relocatable<unique_ptr<T, D>> : bool_constant<is_relocatable_v<D>>
{};

Any comments are welcome!

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ae17c7f0-33c5-4f80-a082-16c8e3e525ae%40isocpp.org.

------=_Part_2622_1336553240.1490686434940
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><font size=3D"4">Introduction</font><div><font size=3D"2">=
I&#39;d like to raise the issue of the=C2=A0<i>relocatable </i>types one mo=
re time. It is well known concept used under different names in the followi=
ng libraries: Folly (IsRelocatable), BDE (IsBitwiseMoveable), EASTL (has_tr=
ivial_relocate), Qt (Q_MOVABLE_TYPE).</font></div><div><font size=3D"2">It =
is natural generalization of the <i>trivially copyable </i>types concept wh=
ich can be used for the=C2=A0</font><span style=3D"font-size: small;">optim=
ization of=C2=A0</span><span style=3D"font-size: small;">objects relocation=
..</span></div><div><span style=3D"font-size: small;"><br></span></div><div>=
<font size=3D"4">Motivation</font></div><div><font size=3D"2">Let&#39;s con=
sider how the operation of std::vector content relocation can be implemente=
d for some complex user defined type T:</font></div><div><font size=3D"2"><=
div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bo=
rder-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; wor=
d-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettypri=
nt"><span style=3D"color: #008;" class=3D"styled-by-prettify">template</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">void</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> relocate</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">T</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">*</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> n=
ew_buffer</span><span style=3D"color: #660;" class=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-by-prettify">*</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> old_buffer</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> size_t size</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>=C2=A0 </span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">for</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">(</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</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #066;" class=3D"styled-by-prettify">0</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> i </span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">!=3D</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> size</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">++=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">i</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">new</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify">new_buffer</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-b=
y-prettify">])</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify">std</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">move_if_noexcept</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">old_buffer</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;" cla=
ss=3D"styled-by-prettify">]));</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br><br>=C2=A0 </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">!=3D</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> size</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">++</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>=C2=A0 =C2=A0 ol=
d_buffer</span><span style=3D"color: #660;" class=3D"styled-by-prettify">[<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">i</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">].~</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">T</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">();</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br></span></div></code></div></font><font size=3D"2">On t=
he other side for trivially copyable types this operation reduces to std::m=
emcpy(new_buffer, old_buffer, size * sizeof(T)). Let&#39;s call the type T =
<i>relocatable </i>if two consequtive calls <div class=3D"prettyprint" styl=
e=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187)=
; border-style: solid; border-width: 1px; word-wrap: break-word;"><code cla=
ss=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008=
;" class=3D"styled-by-prettify">new</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">new_place</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> T</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"styled-by-prettify">::</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">move</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">old_place</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">));</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>old_place</span><span style=3D"color: #660;" =
class=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></div></code></div>can be replaced by memcpy(&amp;new=
_place, &amp;old_place, sizeof(T)). Of course, all trivially copyable types=
 are <i>relocatable </i>by definition. Let&#39;s enumerate some relocatable=
 types from the standard library.</font></div><div><ul><li><font size=3D"2"=
>shared_ptr: move constructor of the shared_ptr and destructor of the empty=
 shared_ptr don&#39;t change shared count.</font></li><li><font size=3D"2">=
unique_ptr&lt;T, D&gt;, if D is relocatable (std::default_delete is trivial=
ly copyable therefore it is relocatable).</font></li><li><font size=3D"2">s=
tring and containers (at least when std::allocator is used).</font></li><li=
><font size=3D"2">optional&lt;T&gt;, variant&lt;Ts...&gt;, if T and Ts... a=
re relocatable.</font></li></ul><div><font size=3D"2">At least following op=
erations from the standard library can be optimized for relocatable types:<=
/font></div><div><ul><li><font size=3D"2">resize of vector,</font></li><li>=
<font size=3D"2">resize of deque,</font></li><li><font size=3D"2">swap of t=
he empty and non-empty optionals,</font></li><li><font size=3D"2">swap of t=
he variants with the different current indices.</font></li></ul><div><font =
size=3D"2">Also it is possible to specialize std::swap for relocatable type=
s and consequently a little optimize some of standard algorithms: *sort*, i=
nplace_merge</font><span style=3D"font-size: small;">, partition</span><spa=
n style=3D"font-size: small;">, unique, rotate, remove*, ...</span></div></=
div></div><div><span style=3D"font-size: small;"><div class=3D"prettyprint"=
 style=3D"border-color: rgb(187, 187, 187); border-style: solid; border-wid=
th: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"=
subprettyprint"><font color=3D"#666600" style=3D"background-color: rgb(250,=
 250, 250);"><span style=3D"color: #008;" class=3D"styled-by-prettify">temp=
late</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">typename</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&gt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span></font><font face=
=3D"Arial, Helvetica, sans-serif" style=3D"color: rgb(102, 102, 0);"><span =
style=3D"color: #000;" class=3D"styled-by-prettify">enable_if_t</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">is_relocatable_v</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">T</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&gt;&gt;</span></font><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> swap</span><span style=3D"color=
: #660;" class=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-by-prettify">&amp;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> x</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> y</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;" c=
lass=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">constexpr</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> size </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">=3D</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><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">T</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br>=C2=A0 aligned_storage_t</span><=
span style=3D"color: #080;" class=3D"styled-by-prettify">&lt;</span><font c=
olor=3D"#000088"><span style=3D"color: #080;" class=3D"styled-by-prettify">=
size</span></font><span style=3D"color: #080;" class=3D"styled-by-prettify"=
>&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> tmp<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 memcpy</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(&amp;</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">tmp</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: #66=
0;" class=3D"styled-by-prettify">&amp;</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">x</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> =C2=A0 size</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>=C2=A0 memcpy</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">(&amp;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">x</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =C2=A0 </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">y</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> =C2=A0 size</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br>=C2=A0 memcpy</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">(&amp;</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify">y</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> =C2=A0 </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">&amp;</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify">tmp</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> size=
</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: #660;" class=3D"styled-by-prettify">}</span></div></code></d=
iv><div><span style=3D"font-size: small;"><br></span></div>Yet another poss=
ible usage of the</span><span style=3D"font-size: small;">=C2=A0</span><spa=
n style=3D"font-size: small;">concept of</span><span style=3D"font-size: sm=
all;">=C2=A0relocatable type is extension of copy ellision. Let&#39;s consi=
der following code fragment:=C2=A0</span></div><div><span style=3D"font-siz=
e: small;"><div class=3D"prettyprint" style=3D"background-color: rgb(250, 2=
50, 250); border-color: rgb(187, 187, 187); border-style: solid; border-wid=
th: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"=
subprettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">v=
ector</span><span style=3D"color: #080;" class=3D"styled-by-prettify">&lt;i=
nt&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> foo=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">bool</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> c</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>=C2=A0 vector</span><span style=3D"color: #080;" clas=
s=3D"styled-by-prettify">&lt;int&gt;</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> xs </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-pretti=
fy">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #066;" class=3D"styled-by-prettify">1</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: #0=
66;" class=3D"styled-by-prettify">2</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: #066;" class=3D"styled-by-pre=
ttify">3</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">},</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> ys </span><span st=
yle=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: #6=
60;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"styl=
ed-by-prettify">4</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #066;" class=3D"styled-by-prettify">5</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=
: #066;" class=3D"styled-by-prettify">6</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>=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-=
by-prettify">if</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify">c</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">return</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> xs</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br>=C2=A0</span><font color=3D"#000088"><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">else</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">return</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> ys</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><br></span><span style=3D"color: #008;" class=3D"styled=
-by-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> result </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
foo</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">rand</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">());</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span></font><font colo=
r=3D"#006666"></font></div></code></div></span>copy ellision doesn&#39;t wo=
rk here, and so `result` will be move constructed, but, in principle, retur=
n value of `foo` can be relocated to `result`.</div><div><br></div><div><fo=
nt size=3D"4">Proposed language changes</font></div><div><ul><li>Define <i =
style=3D"font-size: small;">relocatable types</i><span style=3D"font-size: =
small;">=C2=A0in [basic.types] p9 after </span><i style=3D"font-size: small=
;">trivially copyable types.</i><br></li></ul><div style=3D"text-align: jus=
tify;"><font size=3D"2"><i>... </i>are collectively called <i>trivially cop=
yable types</i>. Trivially copyable types, relocatable classes, arrays of s=
uch types and cv-qualified versions of these types are collectively called =
<i>relocable types</i>.</font></div></div><div style=3D"text-align: justify=
;"><ul><li><font size=3D"2">Define <i>relocatable class </i>in [class] afte=
r <i>trivially copyable class.</i></font></li></ul><div><font size=3D"2">A =
class s is a=C2=A0<i>relocatable class</i> if it either explicitly marked a=
s relocatable or</font></div><div><ol><li><font size=3D"2">all basic classe=
s are relocatable,</font></li><li><font size=3D"2">all non-static data memb=
ers are relocatable,</font></li><li><font size=3D"2">s has a non-virtual, n=
on-deleted and non user-defined destructor.</font></li></ol><div><font size=
=3D"2">It should be discussed how to explicitly mark a class as relocatable=
.. One of the possible solutions is to allow</font><span style=3D"font-size:=
 small;">=C2=A0</span><span style=3D"font-size: small;">specializations of =
the</span><span style=3D"font-size: small;">=C2=A0type trait std::is_reloca=
table. For example,</span></div><div><font size=3D"2"><div class=3D"prettyp=
rint" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187,=
 187, 187); border-style: solid; border-width: 1px; word-wrap: break-word;"=
><code class=3D"prettyprint"><div class=3D"subprettyprint"><font color=3D"#=
666600"><span style=3D"color: #008;" class=3D"styled-by-prettify">template<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> T</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">typename</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> D</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">&gt;</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> is_relocatable</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">unique_ptr</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">T</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> D</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</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"> bool_constant</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">is_relocatable_v</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">D</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">{};</span></font></div></code></div><br></font></div></div><div><fon=
t size=3D"2">Any comments are welcome!</font></div></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/ae17c7f0-33c5-4f80-a082-16c8e3e525ae%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/ae17c7f0-33c5-4f80-a082-16c8e3e525ae=
%40isocpp.org</a>.<br />

------=_Part_2622_1336553240.1490686434940--

------=_Part_2621_396928494.1490686434939--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 28 Mar 2017 09:47:02 +0200
Raw View
On 2017-03-28 09:33, Andrey Davydov wrote:
> Introduction
> I'd like to raise the issue of the /relocatable /types one more time. It
> is well known concept used under different names in the following
> libraries: Folly (IsRelocatable), BDE (IsBitwiseMoveable), EASTL
> (has_trivial_relocate), Qt (Q_MOVABLE_TYPE).
> It is natural generalization of the /trivially copyable /types concept
> which can be used for the optimization of objects relocation.
>
> Motivation
> Let's consider how the operation of std::vector content relocation can
> be implemented for some complex user defined type T:
> |
> template<typenameT>
> voidrelocate(T*new_buffer,T*old_buffer,size_t size)
> {
>   for(size_t i =0;i !=size;++i)
>     new(new_buffer[i])T(std::move_if_noexcept(old_buffer[i]));
>
>   for(size_t i =0;i !=size;++i)
>     old_buffer[i].~T();
> }
> |
> On the other side for trivially copyable types this operation reduces to
> std::memcpy(new_buffer, old_buffer, size * sizeof(T)). Let's call the
> type T /relocatable /if two consequtive calls
> |
> new(new_place)T(std::move(old_place));
> old_place.~T();
> |
> can be replaced by memcpy(&new_place, &old_place, sizeof(T)). Of course,
> all trivially copyable types are /relocatable /by definition. Let's
> enumerate some relocatable types from the standard library.

Well, but ~T does end the lifetime of T, whereas the equivalent "memcpy"
leaves the lifetime of the stuff at old_place untouched.  Not to mention
that bit-blasting doesn't start the lifetime of something at new_place,
either.

>   * shared_ptr: move constructor of the shared_ptr and destructor of the
>     empty shared_ptr don't change shared count.
>   * unique_ptr<T, D>, if D is relocatable (std::default_delete is
>     trivially copyable therefore it is relocatable).
>   * string and containers (at least when std::allocator is used).

What assembly code do you get from the existing move-construct and
destroy operations, compared to memcpy?  Is there something we could
teach the optimizer to help out?

>   * optional<T>, variant<Ts...>, if T and Ts... are relocatable.

[...]

>   * Define /relocatable class /in [class] after /trivially copyable class./
>
> A class s is a /relocatable class/ if it either explicitly marked as
> relocatable or
>
>  1. all basic classes are relocatable,

What are "basic classes"?

>  2. all non-static data members are relocatable,
>  3. s has a non-virtual, non-deleted and non user-defined destructor.

Well, classes that have a pointer to itself are also not relocatable,
but your definition seems to make them so.

> It should be discussed how to explicitly mark a class as relocatable.
> One of the possible solutions is to allow specializations of the type
> trait std::is_relocatable. For example,
> |
> template<typenameT,typenameD>
> structis_relocatable<unique_ptr<T,D>>:bool_constant<is_relocatable_v<D>>{};

I'm opposed to defining core language properties depending on the
specialization of a library-level type trait.

Jens


--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/84dc94a8-fc97-c252-8eb7-c5d3638828f6%40gmx.net.

.


Author: Andrey Davydov <andrey.a.davydov@gmail.com>
Date: Tue, 28 Mar 2017 01:54:05 -0700 (PDT)
Raw View
------=_Part_3718_813042593.1490691245658
Content-Type: multipart/alternative;
 boundary="----=_Part_3719_1152140338.1490691245659"

------=_Part_3719_1152140338.1490691245659
Content-Type: text/plain; charset=UTF-8


>
> Well, but ~T does end the lifetime of T, whereas the equivalent "memcpy"
> leaves the lifetime of the stuff at old_place untouched.  Not to mention
> that bit-blasting doesn't start the lifetime of something at new_place,
> either.
>
It's true, but what practical problems for relocatable types does it cause
to? Is it valid, for example, to implement std::copy of contiguous range of
POD types as one call of memcpy?

>   * shared_ptr: move constructor of the shared_ptr and destructor of the
> >     empty shared_ptr don't change shared count.
> >   * unique_ptr<T, D>, if D is relocatable (std::default_delete is
> >     trivially copyable therefore it is relocatable).
> >   * string and containers (at least when std::allocator is used).
>
> What assembly code do you get from the existing move-construct and
> destroy operations, compared to memcpy?  Is there something we could
> teach the optimizer to help out?
>
I'd like to replace *n* calls of move constructor and *n* calls of
destructor (for std::unique_ptr it, for example, contains *if) *by single
memcpy during resize of std::vector.
Nothing from my proposal (may be, except the extension of copy ellision)
requires additional logic in optimizer or code generator. It's pure
language frontend feature which should be used by library authors.

> >   * Define /relocatable class /in [class] after /trivially copyable
> class./
> >
> > A class s is a /relocatable class/ if it either explicitly marked as
> > relocatable or
> >
> >  1. all basic classes are relocatable,
>
> What are "basic classes"?
>
It's my fault. Of course, there should be "*base* classes".


> >  2. all non-static data members are relocatable,
> >  3. s has a non-virtual, non-deleted and non user-defined destructor.
>
> Well, classes that have a pointer to itself are also not relocatable,
> but your definition seems to make them so.
>
Agree, it is a serious issue. The first thought is to extend list of
requirements by following item:
4. s doesn't have user defined copy constructor, move constructor, copy
assignment operator, and move assignment operator.

>
> > It should be discussed how to explicitly mark a class as relocatable.
> > One of the possible solutions is to allow specializations of the type
> > trait std::is_relocatable. For example,
> > |
> > template<typenameT,typenameD>
> >
> structis_relocatable<unique_ptr<T,D>>:bool_constant<is_relocatable_v<D>>{};
>
> I'm opposed to defining core language properties depending on the
> specialization of a library-level type trait.
>
I also have concern about it. Another possible solution for marking class
as relocatable is to introduce special class std::relocatable_marker and
check that it is a direct base of the defined class. For example,
namespace std
{
  template<bool> struct conditional_relocatable_marker;

  template<>
  struct conditional_relocatable_marker<true>
  {
    using type = relocatable_marker;
  };

  template<>
  struct conditional_relocatable_marker<false>
  {
    struct type {};
  };

  template<typename T, typename D>
  class unique_ptr : typename conditional_relocatable_marker<
is_relocatable_v<D>>::type
  {
    // ...
  };
}


--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/4e80429c-926d-4a5e-9a7b-6e177b954330%40isocpp.org.

------=_Part_3719_1152140338.1490691245659
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;">Well, but ~T =
does end the lifetime of T, whereas the equivalent &quot;memcpy&quot;
<br>leaves the lifetime of the stuff at old_place untouched. =C2=A0Not to m=
ention
<br>that bit-blasting doesn&#39;t start the lifetime of something at new_pl=
ace,
<br>either.
<br></blockquote><div>It&#39;s true, but what practical problems for reloca=
table types does it cause to? Is it valid, for example, to implement std::c=
opy of contiguous range of POD types as one call of memcpy?</div><div><br><=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;">&gt; =C2=A0 * shared_ptr:=
 move constructor of the shared_ptr and destructor of the
<br>&gt; =C2=A0 =C2=A0 empty shared_ptr don&#39;t change shared count.
<br>&gt; =C2=A0 * unique_ptr&lt;T, D&gt;, if D is relocatable (std::default=
_delete is
<br>&gt; =C2=A0 =C2=A0 trivially copyable therefore it is relocatable).
<br>&gt; =C2=A0 * string and containers (at least when std::allocator is us=
ed).
<br>
<br>What assembly code do you get from the existing move-construct and
<br>destroy operations, compared to memcpy? =C2=A0Is there something we cou=
ld
<br>teach the optimizer to help out?<br></blockquote><div>I&#39;d like to r=
eplace <b>n</b> calls of move constructor and <b>n</b> calls of destructor =
(for std::unique_ptr it, for example, contains <b>if) </b>by single memcpy =
during=C2=A0resize of std::vector.</div><div>Nothing from my proposal (may =
be, except the extension of copy ellision) requires additional logic in opt=
imizer or code generator. It&#39;s pure language frontend feature which sho=
uld be used by library authors.</div><blockquote class=3D"gmail_quote" styl=
e=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left:=
 1ex;">&gt; =C2=A0 * Define /relocatable class /in [class] after /trivially=
 copyable class./
<br>&gt;
<br>&gt; A class s is a /relocatable class/ if it either explicitly marked =
as
<br>&gt; relocatable or
<br>&gt;
<br>&gt; =C2=A01. all basic classes are relocatable,
<br>
<br>What are &quot;basic classes&quot;?
<br></blockquote><div>It&#39;s my fault. Of course, there should be &quot;<=
b>base</b> classes&quot;.=C2=A0</div><div>=C2=A0</div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;">&gt; =C2=A02. all non-static data members are reloc=
atable,
<br>&gt; =C2=A03. s has a non-virtual, non-deleted and non user-defined des=
tructor.
<br>
<br>Well, classes that have a pointer to itself are also not relocatable,
<br>but your definition seems to make them so.
<br></blockquote><div>Agree, it is a serious issue. The first thought is to=
 extend list of requirements by following item:</div><div>4. s doesn&#39;t =
have user defined copy constructor, move constructor, copy assignment opera=
tor, and move assignment operator.</div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;">
<br>&gt; It should be discussed how to explicitly mark a class as relocatab=
le.
<br>&gt; One of the possible solutions is to allow specializations of the t=
ype
<br>&gt; trait std::is_relocatable. For example,
<br>&gt; |
<br>&gt; template&lt;typenameT,typenameD&gt;
<br>&gt; structis_relocatable&lt;unique_<wbr>ptr&lt;T,D&gt;&gt;:bool_consta=
nt&lt;is_<wbr>relocatable_v&lt;D&gt;&gt;{};
<br>
<br>I&#39;m opposed to defining core language properties depending on the
<br>specialization of a library-level type trait.<br></blockquote><div>I al=
so have concern about it. Another possible solution for marking class as re=
locatable is to introduce special class std::relocatable_marker and check t=
hat it is a direct base of the defined class. For example,</div><div><div c=
lass=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-=
color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wra=
p: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><=
span style=3D"color: #008;" class=3D"styled-by-prettify">namespace</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> std<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>=C2=A0 </span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">template</span><span style=
=3D"color: #080;" class=3D"styled-by-prettify">&lt;bool&gt;</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">struct</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> conditional_relocatable_marker</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0<br>=C2=A0 </span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">template</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&gt;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> conditional_relocatabl=
e_marker</span><span style=3D"color: #080;" class=3D"styled-by-prettify">&l=
t;true&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br>=C2=A0 </span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify"=
>using</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> typ=
e </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> relocatable_ma=
rker</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 <br>=C2=A0 =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">template</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&gt;</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> conditional_relo=
catable_marker</span><span style=3D"color: #080;" class=3D"styled-by-pretti=
fy">&lt;false&gt;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br>=C2=A0 </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">struct</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> type </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{=
};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 <br=
>=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">te=
mplate</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;=
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">typename</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T</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=
: #008;" class=3D"styled-by-prettify">typename</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> D</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">class</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> unique_ptr </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">typename</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> conditional_relocatable_marker</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">is_relocatable_v</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">D</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&gt;&gt;::</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">type<br>=C2=A0 </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>=C2=A0 =C2=A0 </span><span style=3D"color: #800;" class=3D"styled=
-by-prettify">// ...</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br>=C2=A0 </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></div></code></div><br><br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/4e80429c-926d-4a5e-9a7b-6e177b954330%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/4e80429c-926d-4a5e-9a7b-6e177b954330=
%40isocpp.org</a>.<br />

------=_Part_3719_1152140338.1490691245659--

------=_Part_3718_813042593.1490691245658--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 28 Mar 2017 11:19:30 +0200
Raw View
On 2017-03-28 10:54, Andrey Davydov wrote:
>     Well, but ~T does end the lifetime of T, whereas the equivalent
>     "memcpy"
>     leaves the lifetime of the stuff at old_place untouched.  Not to
>     mention
>     that bit-blasting doesn't start the lifetime of something at new_place,
>     either.
>
> It's true, but what practical problems for relocatable types does it
> cause to?

The concept of "lifetime" is increasingly exploited by optimizers
to determine, for example, possible aliasing.

>   Is it valid, for example, to implement std::copy of contiguous
> range of POD types as one call of memcpy?

Sorry, what's POD doing in this discussion?

>     >   * shared_ptr: move constructor of the shared_ptr and destructor
>     of the
>     >     empty shared_ptr don't change shared count.
>     >   * unique_ptr<T, D>, if D is relocatable (std::default_delete is
>     >     trivially copyable therefore it is relocatable).
>     >   * string and containers (at least when std::allocator is used).
>
>     What assembly code do you get from the existing move-construct and
>     destroy operations, compared to memcpy?  Is there something we could
>     teach the optimizer to help out?
>
> I'd like to replace *n* calls of move constructor and *n* calls of
> destructor (for std::unique_ptr it, for example, contains *if) *by
> single memcpy during resize of std::vector.

Can the optimizer determine that the "if" in unique_ptr's destructor
is redundant for your case?  If not, what's preventing it from doing
so?  Certainly, the move constructor is inlined, so what does it
actually do?  Presumably zero the value that the "if" is checking.

> Nothing from my proposal (may be, except the extension of copy ellision)
> requires additional logic in optimizer or code generator. It's pure
> language frontend feature which should be used by library authors.

I'm questioning whether we need this feature, and exploring how
far we can get using other means.

>     >   * Define /relocatable class /in [class] after /trivially
>     copyable class./
>     >
>     > A class s is a /relocatable class/ if it either explicitly marked as
>     > relocatable or
>     >
>     >  1. all basic classes are relocatable,
>
>     What are "basic classes"?
>
> It's my fault. Of course, there should be "*base* classes".

So, where does this recursion start?  Which types (e.g. built-in types)
are defined to be relocatable to start with?

>
>     >  2. all non-static data members are relocatable,
>     >  3. s has a non-virtual, non-deleted and non user-defined destructor.
>
>     Well, classes that have a pointer to itself are also not relocatable,
>     but your definition seems to make them so.
>
> Agree, it is a serious issue. The first thought is to extend list of
> requirements by following item:
> 4. s doesn't have user defined copy constructor, move constructor, copy
> assignment operator, and move assignment operator.

How is that different from "trivially copyable", then?

>     > It should be discussed how to explicitly mark a class as relocatable.
>     > One of the possible solutions is to allow specializations of the type
>     > trait std::is_relocatable. For example,
>     > |
>     > template<typenameT,typenameD>
>     >
>     structis_relocatable<unique_ptr<T,D>>:bool_constant<is_relocatable_v<D>>{};
>
>
>     I'm opposed to defining core language properties depending on the
>     specialization of a library-level type trait.
>
> I also have concern about it. Another possible solution for marking
> class as relocatable is to introduce special class
> std::relocatable_marker and check that it is a direct base of the
> defined class. For example,

I agree it's a possible solution, but no thanks.

Jens

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/8bb3e8d5-50a3-8128-0b37-2c3da733f245%40gmx.net.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 28 Mar 2017 07:05:08 -0700 (PDT)
Raw View
------=_Part_10280_2119048866.1490709908393
Content-Type: multipart/alternative;
 boundary="----=_Part_10281_1876651473.1490709908393"

------=_Part_10281_1876651473.1490709908393
Content-Type: text/plain; charset=UTF-8

On Tuesday, March 28, 2017 at 4:54:05 AM UTC-4, Andrey Davydov wrote:
>
> Well, but ~T does end the lifetime of T, whereas the equivalent "memcpy"
>> leaves the lifetime of the stuff at old_place untouched.  Not to mention
>> that bit-blasting doesn't start the lifetime of something at new_place,
>> either.
>>
> It's true, but what practical problems for relocatable types does it cause
> to? Is it valid, for example, to implement std::copy of contiguous range of
> POD types as one call of memcpy?
>

If by "POD types" you mean trivially copyable types, then yes it's legal to
use `memcpy` to implement `std::copy`, so long as `T` is copy-assignable
(yes, it is possible to create a `T` which is trivially copyable and yet
not copy-assignable).

>   * shared_ptr: move constructor of the shared_ptr and destructor of the
>> >     empty shared_ptr don't change shared count.
>> >   * unique_ptr<T, D>, if D is relocatable (std::default_delete is
>> >     trivially copyable therefore it is relocatable).
>> >   * string and containers (at least when std::allocator is used).
>>
>> What assembly code do you get from the existing move-construct and
>> destroy operations, compared to memcpy?  Is there something we could
>> teach the optimizer to help out?
>>
> I'd like to replace *n* calls of move constructor and *n* calls of
> destructor (for std::unique_ptr it, for example, contains *if) *by single
> memcpy during resize of std::vector.
>

But you can't really do that. Why? Because you haven't really moved the
object properly.

That's why "relocation" is often called "destructive-move". Because it only
makes sense if the move operation *simultaneously* ends the lifetime of the
old object. Doing just a `memcpy` won't destroy the old objects, and if the
user calls those destructors, bad things happen.

A better way of dealing with this would be to have a function specifically
to invoke a "relocation" operation:

T* std::relocate_and_construct(void *dst, T *src, size_t count = 1);
T* std::relocate_and_assign(T *dst, T *src, size_t count = 1);

Both functions are explicitly defined to end the lifetime of `count`
elements of `src`. The thing is though that they won't call `T`'s
destructor. The lifetime will be ended as if the function had started the
lifetime of some other (trivial) object in that storage.

The first function explicitly begins the lifetime of `T`s within `dst`. The
second function assigns the values to existing `T`s. In both cases, the
return value is a pointer to the newly created `T`s (in the original
storage, of course).

The first function requires that `T` is relocatable and copy constructible.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/d940b395-3430-43dc-a04b-5d1934b26149%40isocpp.org.

------=_Part_10281_1876651473.1490709908393
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Tuesday, March 28, 2017 at 4:54:05 AM UTC-4, Andrey Dav=
ydov wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><b=
lockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-=
left:1px #ccc solid;padding-left:1ex">Well, but ~T does end the lifetime of=
 T, whereas the equivalent &quot;memcpy&quot;
<br>leaves the lifetime of the stuff at old_place untouched. =C2=A0Not to m=
ention
<br>that bit-blasting doesn&#39;t start the lifetime of something at new_pl=
ace,
<br>either.
<br></blockquote><div>It&#39;s true, but what practical problems for reloca=
table types does it cause to? Is it valid, for example, to implement std::c=
opy of contiguous range of POD types as one call of memcpy?</div></div></bl=
ockquote><div><br>If by &quot;POD types&quot; you mean trivially copyable t=
ypes, then yes it&#39;s legal to use `memcpy` to implement `std::copy`, so =
long as `T` is copy-assignable (yes, it is possible to create a `T` which i=
s trivially copyable and yet not copy-assignable).<br><br></div><blockquote=
 class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1=
px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #c=
cc solid;padding-left:1ex">&gt; =C2=A0 * shared_ptr: move constructor of th=
e shared_ptr and destructor of the
<br>&gt; =C2=A0 =C2=A0 empty shared_ptr don&#39;t change shared count.
<br>&gt; =C2=A0 * unique_ptr&lt;T, D&gt;, if D is relocatable (std::default=
_delete is
<br>&gt; =C2=A0 =C2=A0 trivially copyable therefore it is relocatable).
<br>&gt; =C2=A0 * string and containers (at least when std::allocator is us=
ed).
<br>
<br>What assembly code do you get from the existing move-construct and
<br>destroy operations, compared to memcpy? =C2=A0Is there something we cou=
ld
<br>teach the optimizer to help out?<br></blockquote><div>I&#39;d like to r=
eplace <b>n</b> calls of move constructor and <b>n</b> calls of destructor =
(for std::unique_ptr it, for example, contains <b>if) </b>by single memcpy =
during=C2=A0resize of std::vector.</div></div></blockquote><div><br>But you=
 can&#39;t really do that. Why? Because you haven&#39;t really moved the ob=
ject properly.<br><br>That&#39;s why &quot;relocation&quot; is often called=
 &quot;destructive-move&quot;. Because it only makes sense if the move oper=
ation <i>simultaneously</i> ends the lifetime of the old object. Doing just=
 a `memcpy` won&#39;t destroy the old objects, and if the user calls those =
destructors, bad things happen.<br><br>A better way of dealing with this wo=
uld be to have a function specifically to invoke a &quot;relocation&quot; o=
peration:<br><br><div style=3D"background-color: rgb(250, 250, 250); border=
-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; overflo=
w-wrap: break-word;" class=3D"prettyprint"><code class=3D"prettyprint"><div=
 class=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
*</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify">relocate_and_construct<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">void</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">dst</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> T </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">*</span><span style=3D"color: #000;" class=3D"styled-by-prettify">s=
rc</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> size_t count </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">1</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"><br>T</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">relocate_and_assign</span><span style=3D"color: #660;" class=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-by-prettify">*</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify">dst</span><span=
 style=3D"color: #660;" class=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-by-prettify">*</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">src</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> size_t count </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">=
1</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span>=
</div></code></div><br>Both functions are explicitly defined to end the lif=
etime of `count` elements of `src`. The thing is though that they won&#39;t=
 call `T`&#39;s destructor. The lifetime will be ended as if the function h=
ad started the lifetime of some other (trivial) object in that storage.<br>=
<br>The first function explicitly begins the lifetime of `T`s within `dst`.=
 The second function assigns the values to existing `T`s. In both cases, th=
e return value is a pointer to the newly created `T`s (in the original stor=
age, of course).<br><br>The first function requires that `T` is relocatable=
 and copy constructible.<br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/d940b395-3430-43dc-a04b-5d1934b26149%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d940b395-3430-43dc-a04b-5d1934b26149=
%40isocpp.org</a>.<br />

------=_Part_10281_1876651473.1490709908393--

------=_Part_10280_2119048866.1490709908393--

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Tue, 28 Mar 2017 10:05:27 -0400
Raw View
On 2017-03-28 05:19, Jens Maurer wrote:
> How is that different from "trivially copyable", then?

Answering this somewhat out of context... a class like unique_ptr is
obviously *not* trivially copyable, but it *should* be *relocatable*.
Relocatability is a special concept that in some cases needs to be
opt-in that says a type's invariants can be preserved when a) one
creates a new instance of the type that is bitwise-identical to the old
instance *and* then b) drops the old instance on the floor (that is,
ends its lifetime but without executing any destruction code).

Obviously, types with trivial copy construction and trivial destruction
meet these criteria. Such types meet (a) and (b) *independently*, which
is a superset of types which meet (a) and (b) only when those operations
are coupled. We need this feature for the latter category (again,
offering unique_ptr as an example).

The best proposal I recall seeing for this was from J. "Nicol Bolas"
McKesson that IIRC introduced a (defaultable) relocation operator. I'm
not sure what happened to it, though; I don't think it was ever
published in a mailing.

--
Matthew

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/58DA6DA7.1010504%40gmail.com.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 28 Mar 2017 09:19:20 -0700
Raw View
On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 00:33:54 PDT Andrey Davydov w=
rote:
> A class s is a *relocatable class* if it either explicitly marked as
> relocatable or
>=20
>    1. all basic classes are relocatable,
>    2. all non-static data members are relocatable,
>    3. s has a non-virtual, non-deleted and non user-defined destructor.

Classes with user-provided destructors should be allowed to be relocatable=
=20
too.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/6199826.nNqNumnh7F%40tjmaciei-mobl1.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 28 Mar 2017 09:21:56 -0700
Raw View
On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 00:47:02 PDT Jens Maurer wrot=
e:
> > can be replaced by memcpy(&new_place, &old_place, sizeof(T)). Of course=
,
> > all trivially copyable types are /relocatable /by definition. Let's
> > enumerate some relocatable types from the standard library.
>=20
> Well, but ~T does end the lifetime of T, whereas the equivalent "memcpy"
> leaves the lifetime of the stuff at old_place untouched.  Not to mention
> that bit-blasting doesn't start the lifetime of something at new_place,
> either.

Obviously that needs to change. Relocatable types have trivial destructors,=
 so=20
the lifetime of the object is tied to the lifetime of the storage allocatio=
n.

> >   * shared_ptr: move constructor of the shared_ptr and destructor of th=
e
> >  =20
> >     empty shared_ptr don't change shared count.
> >  =20
> >   * unique_ptr<T, D>, if D is relocatable (std::default_delete is
> >  =20
> >     trivially copyable therefore it is relocatable).
> >  =20
> >   * string and containers (at least when std::allocator is used).
>=20
> What assembly code do you get from the existing move-construct and
> destroy operations, compared to memcpy?  Is there something we could
> teach the optimizer to help out?

We cannot. The most important gain we're going to have is not the memcpy, i=
t's=20
the fact that the resize() operation in the container can be implemented by=
 a=20
call to realloc(), as opposed to malloc() + memcpy().

> I'm opposed to defining core language properties depending on the
> specialization of a library-level type trait.

True, but we need to figure out a way.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/2983833.YXtUx8WsmA%40tjmaciei-mobl1.

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 28 Mar 2017 18:31:21 +0200
Raw View
On 2017-03-28 18:21, Thiago Macieira wrote:
> On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 00:47:02 PDT Jens Maurer wr=
ote:
>>> can be replaced by memcpy(&new_place, &old_place, sizeof(T)). Of course=
,
>>> all trivially copyable types are /relocatable /by definition. Let's
>>> enumerate some relocatable types from the standard library.
>>
>> Well, but ~T does end the lifetime of T, whereas the equivalent "memcpy"
>> leaves the lifetime of the stuff at old_place untouched.  Not to mention
>> that bit-blasting doesn't start the lifetime of something at new_place,
>> either.
>
> Obviously that needs to change. Relocatable types have trivial destructor=
s, so
> the lifetime of the object is tied to the lifetime of the storage allocat=
ion.

Specific proposals that include core wording are welcome.

>>>   * shared_ptr: move constructor of the shared_ptr and destructor of th=
e
>>>
>>>     empty shared_ptr don't change shared count.
>>>
>>>   * unique_ptr<T, D>, if D is relocatable (std::default_delete is
>>>
>>>     trivially copyable therefore it is relocatable).
>>>
>>>   * string and containers (at least when std::allocator is used).
>>
>> What assembly code do you get from the existing move-construct and
>> destroy operations, compared to memcpy?

This question is still unanswered.

>  Is there something we could
>> teach the optimizer to help out?
>
> We cannot. The most important gain we're going to have is not the memcpy,=
 it's
> the fact that the resize() operation in the container can be implemented =
by a
> call to realloc(), as opposed to malloc() + memcpy().

The standard allocators (and related containers)
don't have a realloc() interface.

Also, I've seen proposals floating around to allow the allocator to
inform the container of the "real" size that was allocated.  That
appears to mean that any realloc() beyond that will cause a
malloc + memcpy under the hood.

Jens

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/724568b2-ff78-2802-e908-95ef0778584a%40gmx.net.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 28 Mar 2017 09:46:57 -0700
Raw View
On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 09:31:21 PDT Jens Maurer wrot=
e:
> > We cannot. The most important gain we're going to have is not the memcp=
y,
> > it's the fact that the resize() operation in the container can be
> > implemented by a call to realloc(), as opposed to malloc() + memcpy().
>=20
> The standard allocators (and related containers)
> don't have a realloc() interface.

Because it couldn't be used until now. Chicken and the egg.

Qt containers do have the ability to reallocate (we don't use std::allocato=
r).

> Also, I've seen proposals floating around to allow the allocator to
> inform the container of the "real" size that was allocated.  That
> appears to mean that any realloc() beyond that will cause a
> malloc + memcpy under the hood.

Right, we'd like a more powerful allocation mechanism that did that, plus a=
=20
non-relocating reallocation. However, every time that was brought up, it=20
seemed that we couldn't get WG14 on board, so it's unlikely to happen in th=
e C=20
library.

If it won't happen in the C library, we can't have it. We're left with=20
realloc() as it stands. I'd like to use it.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/3152632.InN3LDP2Un%40tjmaciei-mobl1.

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Tue, 28 Mar 2017 12:59:40 -0400
Raw View
On 2017-03-28 12:21, Thiago Macieira wrote:
> On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 00:47:02 PDT Jens Maurer wr=
ote:
>> Well, but ~T does end the lifetime of T, whereas the equivalent "memcpy"
>> leaves the lifetime of the stuff at old_place untouched.  Not to mention
>> that bit-blasting doesn't start the lifetime of something at new_place,
>> either.
>=20
> Obviously that needs to change. Relocatable types have trivial destructor=
s, so=20
> the lifetime of the object is tied to the lifetime of the storage allocat=
ion.

*Not necessarily*. See unique_ptr... relocatable (or should be), but the
default dtor certainly isn't trivial!

As I said in my other message, a relocatable type is one for which copy
construction and destruction are trivial *when those operations are
coupled*. They *do not* need to be individually trivial.

>> What assembly code do you get from the existing move-construct and
>> destroy operations, compared to memcpy?  Is there something we could
>> teach the optimizer to help out?
>=20
> We cannot. The most important gain we're going to have is not the memcpy,=
 it's=20
> the fact that the resize() operation in the container can be implemented =
by a=20
> call to realloc(), as opposed to malloc() + memcpy().

Actually, we can't=C2=B9 even use memcpy now for some relocatable types. Th=
e
*biggest* gain is that a container resize can be implemented with memcpy
instead of (non-trivial) move ctor + dtor for every element.

The real question is if the optimizer can optimize something like:

  auto new_item =3D std::move(old_item);
  ~old_item;

....to just a memcpy, if the dtor is non-trivial but has no side effects
if the object being destroyed is moved-from. Keep in mind this includes
being able to tell that the side effects of the move ctor on the *old*
object become dead code that can be elided. Then add to the above
trivial example that you are doing this for a lot of objects at once,
and the destruction does not immediately follow move construction
(especially when it's via `delete[]`). Also keep in mind that to
"succeed" here, the optimizer also has to be able to detect and merge
adjacent memcpy's.

This assumes that the ctor and dtor are both inline; if either is in a
separate TU, then you're SOL. (Such a class could still have a defaulted
relocation operation!)

(=C2=B9 Various libraries' containers =E2=80=94 including Qt's =E2=80=94 do=
 it anyway, but
it's technically UB. The whole point is to a) be able to do it *without*
UB, and b) using a standardized mechanism that anyone implementing their
own container can use.)

--=20
Matthew

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/58DA967C.3000501%40gmail.com.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 28 Mar 2017 10:20:24 -0700 (PDT)
Raw View
------=_Part_14115_257697942.1490721625110
Content-Type: multipart/alternative;
 boundary="----=_Part_14116_1102725872.1490721625110"

------=_Part_14116_1102725872.1490721625110
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable



On Tuesday, March 28, 2017 at 12:22:05 PM UTC-4, Thiago Macieira wrote:
>
> On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 00:47:02 PDT Jens Maurer wr=
ote:=20
> > > can be replaced by memcpy(&new_place, &old_place, sizeof(T)). Of=20
> course,=20
> > > all trivially copyable types are /relocatable /by definition. Let's=
=20
> > > enumerate some relocatable types from the standard library.=20
> >=20
> > Well, but ~T does end the lifetime of T, whereas the equivalent "memcpy=
"=20
> > leaves the lifetime of the stuff at old_place untouched.  Not to mentio=
n=20
> > that bit-blasting doesn't start the lifetime of something at new_place,=
=20
> > either.=20
>
> Obviously that needs to change. Relocatable types have trivial=20
> destructors, so=20
> the lifetime of the object is tied to the lifetime of the storage=20
> allocation.
>

But they don't. `unique_ptr` does not have a trivial destructor. This is=20
why it's important for the relocation operation to explicitly terminate the=
=20
lifetime of the input value. Because for relocation to work, that=20
termination cannot call the destructor.

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/faf8b9cc-2a7f-45b8-8687-9dd38c73464f%40isocpp.or=
g.

------=_Part_14116_1102725872.1490721625110
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Tuesday, March 28, 2017 at 12:22:05 PM UTC-4, T=
hiago Macieira wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;m=
argin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On ter=C3=
=A7a-feira, 28 de mar=C3=A7o de 2017 00:47:02 PDT Jens Maurer wrote:
<br>&gt; &gt; can be replaced by memcpy(&amp;new_place, &amp;old_place, siz=
eof(T)). Of course,
<br>&gt; &gt; all trivially copyable types are /relocatable /by definition.=
 Let&#39;s
<br>&gt; &gt; enumerate some relocatable types from the standard library.
<br>&gt;=20
<br>&gt; Well, but ~T does end the lifetime of T, whereas the equivalent &q=
uot;memcpy&quot;
<br>&gt; leaves the lifetime of the stuff at old_place untouched. =C2=A0Not=
 to mention
<br>&gt; that bit-blasting doesn&#39;t start the lifetime of something at n=
ew_place,
<br>&gt; either.
<br>
<br>Obviously that needs to change. Relocatable types have trivial destruct=
ors, so=20
<br>the lifetime of the object is tied to the lifetime of the storage alloc=
ation.<br></blockquote><div><br>But they don&#39;t. `unique_ptr` does not h=
ave a trivial destructor. This is why it&#39;s important for the relocation=
 operation to explicitly terminate the lifetime of the input value. Because=
 for relocation to work, that termination cannot call the destructor.<br></=
div><br></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/faf8b9cc-2a7f-45b8-8687-9dd38c73464f%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/faf8b9cc-2a7f-45b8-8687-9dd38c73464f=
%40isocpp.org</a>.<br />

------=_Part_14116_1102725872.1490721625110--

------=_Part_14115_257697942.1490721625110--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 28 Mar 2017 19:46:57 +0200
Raw View
On 2017-03-28 18:46, Thiago Macieira wrote:
> Qt containers do have the ability to reallocate (we don't use std::allocator).

How do those containers deal with the lifetime issues?

>> Also, I've seen proposals floating around to allow the allocator to
>> inform the container of the "real" size that was allocated.  That
>> appears to mean that any realloc() beyond that will cause a
>> malloc + memcpy under the hood.
>
> Right, we'd like a more powerful allocation mechanism that did that, plus a
> non-relocating reallocation. However, every time that was brought up, it
> seemed that we couldn't get WG14 on board, so it's unlikely to happen in the C
> library.
>
> If it won't happen in the C library, we can't have it.

Why?  The C++ interface to allocation is "new" and "delete",
not "malloc" and "free".

Jens

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f4dacf27-31d0-8239-99d0-1dbbf3bfc7fa%40gmx.net.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 28 Mar 2017 10:50:57 -0700
Raw View
On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 10:20:24 PDT Nicol Bolas wrot=
e:
> > Obviously that needs to change. Relocatable types have trivial
> > destructors, so
> > the lifetime of the object is tied to the lifetime of the storage
> > allocation.
>=20
> But they don't. `unique_ptr` does not have a trivial destructor. This is
> why it's important for the relocation operation to explicitly terminate t=
he
> lifetime of the input value. Because for relocation to work, that
> termination cannot call the destructor.

Right.

I think we need to analyse this in the context of a larger problem, otherwi=
se=20
we won't solve the long-term problems.

First, there's the destructive move, an operation that ties both a move=20
construction of the destination with the destruction of the source. It need=
s=20
to be a new function that one can add to their class. In most cases, it wil=
l=20
be what the move constructor does, except that it knows the source will nev=
er=20
ever be used again, so it need not leave that in a valid state.

For example, for std::shared_ptr:
 - copy: increase reference count, leave source unchanged
 - move: no change in reference count, reset source to empty
 - move-destruct: no change in reference count, leave source unchanged

Second, we need a way to invoke this operation. It's not simply
 a =3D std::move(b);

It could be:

 template <typename T>
 T *move_destroy(T *dest, T *source, size_t count =3D 1);

a function that requires ABI knowledge and possibly intrinsics. We also nee=
d=20
to solve the problem of whether the size cookie should be copied (probably=
=20
not).

Third, we have the relocation, which is a special case of move-destruction=
=20
that is a simple memcpy and abandon source.

Fourth, we have the case of triviality. A class that is trivially move=20
constructible and trivially destructible is trivially move-destructible. A=
=20
trivial move-destruction is a memcpy and abandon, so trivial move-destructi=
on=20
is relocation.

The reason I'm separating the concerns here is that a type could implement =
a=20
move-destruction which is not simple memcpy + drop. I don't know if we coul=
d=20
say that a complex type with non-trivial move constructor and non-trivial=
=20
destructor could have trivial move-destructor. If we can, then the concept =
of=20
trivial move destruction is the same as relocation.

Finally, there's realloc() and lifetimes. I want to apply realloc() to=20
anything that is relocatable, whether it has trivial constructor and=20
destructor or not.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/6467623.X9JsKb3z4v%40tjmaciei-mobl1.

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Tue, 28 Mar 2017 14:07:18 -0400
Raw View
On 2017-03-28 13:50, Thiago Macieira wrote:
> Third, we have the relocation, which is a special case of move-destruction
> that is a simple memcpy and abandon source.

Uh...

> Fourth, we have the case of triviality. A class that is trivially move
> constructible and trivially destructible is trivially move-destructible. A
> trivial move-destruction is a memcpy and abandon, so trivial move-destruction
> is relocation.

Okay, ugh... what I think most of us call "relocation" you are calling
"move-destruction". Can we please stick to "relocation" (what you call
move-destruction) and "trivial relocation" (what you call relocation)?

> I don't know if we could say that a complex type with non-trivial
> move constructor and non-trivial destructor could have trivial
> move-destructor.

We can, and we need to be able to do so, for unique_ptr and similar classes.

--
Matthew

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/58DAA656.8040605%40gmail.com.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 28 Mar 2017 11:10:55 -0700 (PDT)
Raw View
------=_Part_11167_76195365.1490724655100
Content-Type: multipart/alternative;
 boundary="----=_Part_11168_708836422.1490724655100"

------=_Part_11168_708836422.1490724655100
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable



On Tuesday, March 28, 2017 at 1:51:03 PM UTC-4, Thiago Macieira wrote:
>
> On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 10:20:24 PDT Nicol Bolas wr=
ote:=20
> > > Obviously that needs to change. Relocatable types have trivial=20
> > > destructors, so=20
> > > the lifetime of the object is tied to the lifetime of the storage=20
> > > allocation.=20
> >=20
> > But they don't. `unique_ptr` does not have a trivial destructor. This i=
s=20
> > why it's important for the relocation operation to explicitly terminate=
=20
> the=20
> > lifetime of the input value. Because for relocation to work, that=20
> > termination cannot call the destructor.=20
>
> Right.=20
>
> I think we need to analyse this in the context of a larger problem,=20
> otherwise=20
> we won't solve the long-term problems.=20
>
> First, there's the destructive move, an operation that ties both a move=
=20
> construction of the destination with the destruction of the source. It=20
> needs=20
> to be a new function that one can add to their class. In most cases, it=
=20
> will=20
> be what the move constructor does, except that it knows the source will=
=20
> never=20
> ever be used again, so it need not leave that in a valid state.
>

It's not just that it doesn't leave it in a valid state. From a wording=20
perspective, this operation must *terminate* the lifetime of the old object=
..

Otherwise, the lifetime hasn't ended and the source is still a live object.

For example, for std::shared_ptr:=20
>         - copy: increase reference count, leave source unchanged=20
>         - move: no change in reference count, reset source to empty=20
>         - move-destruct: no change in reference count, leave source=20
> unchanged=20
>
> Second, we need a way to invoke this operation. It's not simply=20
>         a =3D std::move(b);=20
>
> It could be:=20
>
>         template <typename T>=20
>         T *move_destroy(T *dest, T *source, size_t count =3D 1);=20
>
> a function that requires ABI knowledge and possibly intrinsics. We also=
=20
> need=20
> to solve the problem of whether the size cookie should be copied (probabl=
y=20
> not).=20
>
> Third, we have the relocation, which is a special case of move-destructio=
n=20
> that is a simple memcpy and abandon source.
>

I'm not sure I agree with the need for such a back-door. It seems to me=20
that, if `T` is trivially move-destructible, `move_destroy` can do this=20
just fine. We shouldn't encourage people to use memcpy&drop instead of the=
=20
equally-performance-friendly alternative.

Fourth, we have the case of triviality. A class that is trivially move=20
> constructible and trivially destructible is trivially move-destructible. =
A=20
> trivial move-destruction is a memcpy and abandon, so trivial=20
> move-destruction=20
> is relocation.
>

But we also need to recognize that users need to declare a type which is=20
not trivially moveable nor trivially destructible is trivially=20
move-destructible. `unique_ptr` being the perfect example (assuming the=20
deleter type is empty or is trivially move-destructible); there is no=20
reason `unique_ptr<T>` should have a non-trivial move-destruction operator.

So we need to be able to declare that a type's move-destruction operation=
=20
is trivial, even if its other operations like trivial copy and so forth are=
=20
non-trivial.

The reason I'm separating the concerns here is that a type could implement=
=20
> a=20
> move-destruction which is not simple memcpy + drop.


Here's the question I have for that: why implement move-destruction at all=
=20
in that case? If your type needs to do actual work in its move-destructor,=
=20
why bother? The `move_destroy` call is going to have to loop over `count`=
=20
and call your move-destruction function. How will that perform better than=
=20
calling the move constructor, followed by the destructor?

Also, move-destruction cannot *ever* throw.

It seems to me that there are really only two types:=20
trivially-move-destructible types and types that cannot be move-destructed.=
=20
The third type, non-trivial move destruction, seems rather pointless.
=20

> I don't know if we could say that a complex type with non-trivial move=20
> constructor and non-trivial destructor could have trivial move-destructor=
..


`unique_ptr`.
=20

> If we can, then the concept of=20
> trivial move destruction is the same as relocation.=20
>
> Finally, there's realloc() and lifetimes. I want to apply realloc() to=20
> anything that is relocatable, whether it has trivial constructor and=20
> destructor or not.=20
>

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/df67a611-b8c1-4420-b513-cf16e837cd7d%40isocpp.or=
g.

------=_Part_11168_708836422.1490724655100
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Tuesday, March 28, 2017 at 1:51:03 PM UTC-4, Th=
iago Macieira wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On ter=C3=
=A7a-feira, 28 de mar=C3=A7o de 2017 10:20:24 PDT Nicol Bolas wrote:
<br>&gt; &gt; Obviously that needs to change. Relocatable types have trivia=
l
<br>&gt; &gt; destructors, so
<br>&gt; &gt; the lifetime of the object is tied to the lifetime of the sto=
rage
<br>&gt; &gt; allocation.
<br>&gt;=20
<br>&gt; But they don&#39;t. `unique_ptr` does not have a trivial destructo=
r. This is
<br>&gt; why it&#39;s important for the relocation operation to explicitly =
terminate the
<br>&gt; lifetime of the input value. Because for relocation to work, that
<br>&gt; termination cannot call the destructor.
<br>
<br>Right.
<br>
<br>I think we need to analyse this in the context of a larger problem, oth=
erwise=20
<br>we won&#39;t solve the long-term problems.
<br>
<br>First, there&#39;s the destructive move, an operation that ties both a =
move=20
<br>construction of the destination with the destruction of the source. It =
needs=20
<br>to be a new function that one can add to their class. In most cases, it=
 will=20
<br>be what the move constructor does, except that it knows the source will=
 never=20
<br>ever be used again, so it need not leave that in a valid state.<br></bl=
ockquote><div><br>It&#39;s not just that it doesn&#39;t leave it in a valid=
 state. From a wording perspective, this operation must <i>terminate</i> th=
e lifetime of the old object.<br><br>Otherwise, the lifetime hasn&#39;t end=
ed and the source is still a live object.<br><br></div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;">
For example, for std::shared_ptr:
<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0- copy: increase refere=
nce count, leave source unchanged
<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0- move: no change in re=
ference count, reset source to empty
<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0- move-destruct: no cha=
nge in reference count, leave source unchanged
<br>
<br>Second, we need a way to invoke this operation. It&#39;s not simply
<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a =3D std::move(b);
<br>
<br>It could be:
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0template &lt;typename T=
&gt;
<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T *move_destroy(T *dest=
, T *source, size_t count =3D 1);
<br>
<br>a function that requires ABI knowledge and possibly intrinsics. We also=
 need=20
<br>to solve the problem of whether the size cookie should be copied (proba=
bly=20
<br>not).
<br>
<br>Third, we have the relocation, which is a special case of move-destruct=
ion=20
<br>that is a simple memcpy and abandon source.<br></blockquote><div><br>I&=
#39;m not sure I agree with the need for such a back-door. It seems to me t=
hat, if `T` is trivially move-destructible, `move_destroy` can do this just=
 fine. We shouldn&#39;t encourage people to use memcpy&amp;drop instead of =
the equally-performance-friendly alternative.<br><br></div><blockquote clas=
s=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #c=
cc solid;padding-left: 1ex;">
Fourth, we have the case of triviality. A class that is trivially move=20
<br>constructible and trivially destructible is trivially move-destructible=
.. A=20
<br>trivial move-destruction is a memcpy and abandon, so trivial move-destr=
uction=20
<br>is relocation.<br></blockquote><div><br>But we also need to recognize t=
hat users need to declare a type which is not trivially moveable nor trivia=
lly destructible is trivially move-destructible. `unique_ptr` being the per=
fect example (assuming the deleter type is empty or is trivially move-destr=
uctible); there is no reason `unique_ptr&lt;T&gt;` should have a non-trivia=
l move-destruction operator.<br><br>So we need to be able to declare that a=
 type&#39;s move-destruction operation is trivial, even if its other operat=
ions like trivial copy and so forth are non-trivial.<br><br></div><blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
 1px #ccc solid;padding-left: 1ex;">
The reason I&#39;m separating the concerns here is that a type could implem=
ent a=20
<br>move-destruction which is not simple memcpy + drop.</blockquote><div><b=
r>Here&#39;s the question I have for that: why implement move-destruction a=
t all in that case? If your type needs to do actual work in its move-destru=
ctor, why bother? The `move_destroy` call is going to have to loop over `co=
unt` and call your move-destruction function. How will that perform better =
than calling the move constructor, followed by the destructor?<br><br>Also,=
 move-destruction cannot <i>ever</i> throw.<br><br>It seems to me that ther=
e are really only two types: trivially-move-destructible types and types th=
at cannot be move-destructed. The third type, non-trivial move destruction,=
 seems rather pointless.<br>=C2=A0</div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;">I don&#39;t know if we could=20
say that a complex type with non-trivial move constructor and non-trivial d=
estructor could have trivial move-destructor.</blockquote><div><br>`unique_=
ptr`.<br>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;m=
argin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">If we can=
, then the concept of=20
<br>trivial move destruction is the same as relocation.
<br>
<br>Finally, there&#39;s realloc() and lifetimes. I want to apply realloc()=
 to=20
<br>anything that is relocatable, whether it has trivial constructor and=20
<br>destructor or not.
<br></blockquote></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/df67a611-b8c1-4420-b513-cf16e837cd7d%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/df67a611-b8c1-4420-b513-cf16e837cd7d=
%40isocpp.org</a>.<br />

------=_Part_11168_708836422.1490724655100--

------=_Part_11167_76195365.1490724655100--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 28 Mar 2017 11:13:50 -0700 (PDT)
Raw View
------=_Part_11191_1945838932.1490724830701
Content-Type: multipart/alternative;
 boundary="----=_Part_11192_2037765205.1490724830701"

------=_Part_11192_2037765205.1490724830701
Content-Type: text/plain; charset=UTF-8

On Tuesday, March 28, 2017 at 2:07:21 PM UTC-4, Matthew Woehlke wrote:
>
> On 2017-03-28 13:50, Thiago Macieira wrote:
> > Fourth, we have the case of triviality. A class that is trivially move
> > constructible and trivially destructible is trivially move-destructible.
> A
> > trivial move-destruction is a memcpy and abandon, so trivial
> move-destruction
> > is relocation.
>
> Okay, ugh... what I think most of us call "relocation" you are calling
> "move-destruction". Can we please stick to "relocation" (what you call
> move-destruction) and "trivial relocation" (what you call relocation)?
>

The problem is that this discussion is not new. Some people call it
"relocation". Others "destructive-move". There have been several formal
proposals for doing it.

This is well-trod ground, and the terminology for it changes with every
iteration.

And personally, I think destructive-move is the right wording. It is vital
to recognize the importance that the operation simultaneously ends the
lifetime of the old object. Because without that, you break the object
model.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/3b4bf77f-e919-40dd-84f5-b76c958a868f%40isocpp.org.

------=_Part_11192_2037765205.1490724830701
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Tuesday, March 28, 2017 at 2:07:21 PM UTC-4, Matthew Wo=
ehlke wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 2017-03-28 13:5=
0, Thiago Macieira wrote:
<br>&gt; Fourth, we have the case of triviality. A class that is trivially =
move=20
<br>&gt; constructible and trivially destructible is trivially move-destruc=
tible. A=20
<br>&gt; trivial move-destruction is a memcpy and abandon, so trivial move-=
destruction=20
<br>&gt; is relocation.
<br>
<br>Okay, ugh... what I think most of us call &quot;relocation&quot; you ar=
e calling
<br>&quot;move-destruction&quot;. Can we please stick to &quot;relocation&q=
uot; (what you call
<br>move-destruction) and &quot;trivial relocation&quot; (what you call rel=
ocation)?<br></blockquote><div><br>The problem is that this discussion is n=
ot new. Some people call it &quot;relocation&quot;. Others &quot;destructiv=
e-move&quot;. There have been several formal proposals for doing it.<br><br=
>This is well-trod ground, and the terminology for it changes with every it=
eration.</div><br>And personally, I think destructive-move is the right wor=
ding. It is vital to recognize the importance that the operation simultaneo=
usly ends the lifetime of the old object. Because without that, you break t=
he object model.<br></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/3b4bf77f-e919-40dd-84f5-b76c958a868f%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/3b4bf77f-e919-40dd-84f5-b76c958a868f=
%40isocpp.org</a>.<br />

------=_Part_11192_2037765205.1490724830701--

------=_Part_11191_1945838932.1490724830701--

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Tue, 28 Mar 2017 14:32:34 -0400
Raw View
On 2017-03-28 14:13, Nicol Bolas wrote:
> On Tuesday, March 28, 2017 at 2:07:21 PM UTC-4, Matthew Woehlke wrote:
>> On 2017-03-28 13:50, Thiago Macieira wrote:
>>> Fourth, we have the case of triviality. A class that is
>>> trivially move constructible and trivially destructible is
>>> trivially move-destructible. A trivial move-destruction is a
>>> memcpy and abandon, so trivial move-destruction is relocation.
>>
>> Okay, ugh... what I think most of us call "relocation" you are
>> calling "move-destruction". Can we please stick to "relocation"
>> (what you call move-destruction) and "trivial relocation" (what you
>> call relocation)?
>
> The problem is that this discussion is not new. Some people call it
> "relocation". Others "destructive-move". There have been several formal
> proposals for doing it.
>
> This is well-trod ground, and the terminology for it changes with every
> iteration.
>
> And personally, I think destructive-move is the right wording. It is vital
> to recognize the importance that the operation simultaneously ends the
> lifetime of the old object. Because without that, you break the object
> model.

Honestly, I can live with either... what I find objectionable is using
two *different* terms, "A" and "B", instead of "A" and "trivial A", and
in particular, defining "B" as a trivial operation when it doesn't have
"trivial" in the name (because what you really mean by "B" is "trivial A").

Please don't do that :-).

--
Matthew

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/58DAAC42.7030201%40gmail.com.

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Tue, 28 Mar 2017 14:40:34 -0400
Raw View
On 2017-03-28 14:10, Nicol Bolas wrote:
> On 2017-03-28 13:50, Thiago Macieira wrote:
>> The reason I'm separating the concerns here is that a type could implement
>> a move-destruction which is not simple memcpy + drop.
>
> Here's the question I have for that: why implement move-destruction at all
> in that case? If your type needs to do actual work in its move-destructor,
> why bother? The `move_destroy` call is going to have to loop over `count`
> and call your move-destruction function. How will that perform better than
> calling the move constructor, followed by the destructor?

Let's say I have a type that has pointer members that relate to `this`.
It is not trivially move-destructible since it needs to fix up these
pointers when it is relocated. But it might need to do complicated
things in its move ctor and/or dtor.

Rare? Probably, but what's the value in precluding the possibility?

--
Matthew

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/58DAAE22.3060404%40gmail.com.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 28 Mar 2017 11:54:37 -0700 (PDT)
Raw View
------=_Part_8460_26719661.1490727277358
Content-Type: multipart/alternative;
 boundary="----=_Part_8461_1732051153.1490727277358"

------=_Part_8461_1732051153.1490727277358
Content-Type: text/plain; charset=UTF-8



On Tuesday, March 28, 2017 at 2:40:37 PM UTC-4, Matthew Woehlke wrote:
>
> On 2017-03-28 14:10, Nicol Bolas wrote:
> > On 2017-03-28 13:50, Thiago Macieira wrote:
> >> The reason I'm separating the concerns here is that a type could
> implement
> >> a move-destruction which is not simple memcpy + drop.
> >
> > Here's the question I have for that: why implement move-destruction at
> all
> > in that case? If your type needs to do actual work in its
> move-destructor,
> > why bother? The `move_destroy` call is going to have to loop over
> `count`
> > and call your move-destruction function. How will that perform better
> than
> > calling the move constructor, followed by the destructor?
>
> Let's say I have a type that has pointer members that relate to `this`.
> It is not trivially move-destructible since it needs to fix up these
> pointers when it is relocated. But it might need to do complicated
> things in its move ctor and/or dtor.
>
> Rare? Probably, but what's the value in precluding the possibility?
>

It makes declaring a type to be move-destructibe/relocatable/etc to mean
something very specific about the nature of that operation.

The only advantage I could see in your case would be if the move
constructor would have to be non-`noexcept`, while the destructive-move
function could be `noexcept`.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ec95f92b-727d-4c29-8d73-719e0f993726%40isocpp.org.

------=_Part_8461_1732051153.1490727277358
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Tuesday, March 28, 2017 at 2:40:37 PM UTC-4, Ma=
tthew Woehlke wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 2017-03=
-28 14:10, Nicol Bolas wrote:
<br>&gt; On 2017-03-28 13:50, Thiago Macieira wrote:
<br>&gt;&gt; The reason I&#39;m separating the concerns here is that a type=
 could implement=20
<br>&gt;&gt; a move-destruction which is not simple memcpy + drop.
<br>&gt;=20
<br>&gt; Here&#39;s the question I have for that: why implement move-destru=
ction at all=20
<br>&gt; in that case? If your type needs to do actual work in its move-des=
tructor,=20
<br>&gt; why bother? The `move_destroy` call is going to have to loop over =
`count`=20
<br>&gt; and call your move-destruction function. How will that perform bet=
ter than=20
<br>&gt; calling the move constructor, followed by the destructor?
<br>
<br>Let&#39;s say I have a type that has pointer members that relate to `th=
is`.
<br>It is not trivially move-destructible since it needs to fix up these
<br>pointers when it is relocated. But it might need to do complicated
<br>things in its move ctor and/or dtor.
<br>
<br>Rare? Probably, but what&#39;s the value in precluding the possibility?=
<br></blockquote><div><br></div>It makes declaring a type to be move-destru=
ctibe/relocatable/etc to mean something very specific about the nature of t=
hat operation.<br><br>The only advantage I could see in your case would be =
if the move constructor would have to be non-`noexcept`, while the destruct=
ive-move function could be `noexcept`.<br></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/ec95f92b-727d-4c29-8d73-719e0f993726%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/ec95f92b-727d-4c29-8d73-719e0f993726=
%40isocpp.org</a>.<br />

------=_Part_8461_1732051153.1490727277358--

------=_Part_8460_26719661.1490727277358--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 28 Mar 2017 22:33:52 +0300
Raw View
On 28 March 2017 at 21:10, Nicol Bolas <jmckesson@gmail.com> wrote:
> It's not just that it doesn't leave it in a valid state. From a wording
> perspective, this operation must terminate the lifetime of the old object.

That is far beyond something from a wording perspective; it's the
fundamental issue
why destructive move proposals thus far haven't been accepted. The motivation of
a destructive move has not been strong enough to add a new way of
ending the lifetime
of an object. Let alone starting to talk about a new kind of a special
member function,
or new kinds of type classifications.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUb0ri7VJva86OBys40mCz5fWMNC1vr5vngmQC1c%2BNAHiA%40mail.gmail.com.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 28 Mar 2017 12:52:46 -0700 (PDT)
Raw View
------=_Part_13767_406294699.1490730766971
Content-Type: multipart/alternative;
 boundary="----=_Part_13768_2076979372.1490730766971"

------=_Part_13768_2076979372.1490730766971
Content-Type: text/plain; charset=UTF-8



On Tuesday, March 28, 2017 at 3:33:54 PM UTC-4, Ville Voutilainen wrote:
>
> On 28 March 2017 at 21:10, Nicol Bolas <jmck...@gmail.com <javascript:>>
> wrote:
> > It's not just that it doesn't leave it in a valid state. From a wording
> > perspective, this operation must terminate the lifetime of the old
> object.
>
> That is far beyond something from a wording perspective; it's the
> fundamental issue
> why destructive move proposals thus far haven't been accepted. The
> motivation of
> a destructive move has not been strong enough to add a new way of
> ending the lifetime
> of an object. Let alone starting to talk about a new kind of a special
> member function,
> or new kinds of type classifications.
>

So the already explained performance improvements are not strong enough of
a motivation? I really don't understand that kind of thinking. What exactly
do people have to do to show you why this functionality is needed? What
exactly would be good enough for you?

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/6da51119-3347-4ca6-8b24-0f790fa5a639%40isocpp.org.

------=_Part_13768_2076979372.1490730766971
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Tuesday, March 28, 2017 at 3:33:54 PM UTC-4, Vi=
lle Voutilainen wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 28 Ma=
rch 2017 at 21:10, Nicol Bolas &lt;<a href=3D"javascript:" target=3D"_blank=
" gdf-obfuscated-mailto=3D"GhoeYbDMBwAJ" rel=3D"nofollow" onmousedown=3D"th=
is.href=3D&#39;javascript:&#39;;return true;" onclick=3D"this.href=3D&#39;j=
avascript:&#39;;return true;">jmck...@gmail.com</a>&gt; wrote:
<br>&gt; It&#39;s not just that it doesn&#39;t leave it in a valid state. F=
rom a wording
<br>&gt; perspective, this operation must terminate the lifetime of the old=
 object.
<br>
<br>That is far beyond something from a wording perspective; it&#39;s the
<br>fundamental issue
<br>why destructive move proposals thus far haven&#39;t been accepted. The =
motivation of
<br>a destructive move has not been strong enough to add a new way of
<br>ending the lifetime
<br>of an object. Let alone starting to talk about a new kind of a special
<br>member function,
<br>or new kinds of type classifications.<br></blockquote><div><br>So the a=
lready explained performance improvements are not strong enough of a motiva=
tion? I really don&#39;t understand that kind of thinking. What exactly do =
people have to do to show you why this functionality is needed? What exactl=
y would be good enough for you?<br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/6da51119-3347-4ca6-8b24-0f790fa5a639%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/6da51119-3347-4ca6-8b24-0f790fa5a639=
%40isocpp.org</a>.<br />

------=_Part_13768_2076979372.1490730766971--

------=_Part_13767_406294699.1490730766971--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 28 Mar 2017 23:20:25 +0300
Raw View
On 28 March 2017 at 22:52, Nicol Bolas <jmckesson@gmail.com> wrote:
>> That is far beyond something from a wording perspective; it's the
>> fundamental issue
>> why destructive move proposals thus far haven't been accepted. The
>> motivation of
>> a destructive move has not been strong enough to add a new way of
>> ending the lifetime
>> of an object. Let alone starting to talk about a new kind of a special
>> member function,
>> or new kinds of type classifications.
> So the already explained performance improvements are not strong enough of a
> motivation? I really don't understand that kind of thinking. What exactly do

The *"explained"* performance benefits? Show us hard numbers, and show
that similar
improvements aren't achievable without fundamental changes to the
object and memory model.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUbrUu7Su0EUdVioxD%2Bh%3DvPyVv8xbt4_7sLa%2Bp1xP7gG0Q%40mail.gmail.com.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 28 Mar 2017 13:41:11 -0700 (PDT)
Raw View
------=_Part_15053_260405871.1490733671151
Content-Type: multipart/alternative;
 boundary="----=_Part_15054_341767830.1490733671152"

------=_Part_15054_341767830.1490733671152
Content-Type: text/plain; charset=UTF-8

On Tuesday, March 28, 2017 at 4:20:27 PM UTC-4, Ville Voutilainen wrote:
>
> On 28 March 2017 at 22:52, Nicol Bolas <jmck...@gmail.com <javascript:>>
> wrote:
> >> That is far beyond something from a wording perspective; it's the
> >> fundamental issue
> >> why destructive move proposals thus far haven't been accepted. The
> >> motivation of
> >> a destructive move has not been strong enough to add a new way of
> >> ending the lifetime
> >> of an object. Let alone starting to talk about a new kind of a special
> >> member function,
> >> or new kinds of type classifications.
> > So the already explained performance improvements are not strong enough
> of a
> > motivation? I really don't understand that kind of thinking. What
> exactly do
>
> The *"explained"* performance benefits? Show us hard numbers, and show
> that similar
> improvements aren't achievable without fundamental changes to the
> object and memory model.
>

No "fundamental changes to the object and memory model" are being proposed.
At its most minimal, there is a single function which has a part of its
definition that it ends the lifetime of one of its parameters.

Ending the lifetime of an object without calling the destructor is legal.
Right now, in the memory model as it currently stands: [basic.life]/5

> For an object of a class type with a non-trivial destructor, the program
is not required to call the destructor explicitly before the storage which
the object occupies is reused or released; however, if there is no explicit
call to the destructor or if a delete-expression (8.3.5) is not used to
release the storage, the destructor shall not be implicitly called and
any program that depends on the side effects produced by the destructor has
undefined behavior.

A type which is relocatable/destructive-moveable is essentially saying,
"when invoking the relocation/destructive-move operation, this program does
not depend on side effects produced by the destructor of this type." And
therefore, the destructive move operation is able to say "I'm ending the
lifetime of the source object(s)."

The object and memory models are unchanged. We're simply using what the
memory model currently allows, in a way that other types can key off of.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/8e05d603-f79e-4e95-b3c6-37cfa9ce41b7%40isocpp.org.

------=_Part_15054_341767830.1490733671152
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Tuesday, March 28, 2017 at 4:20:27 PM UTC-4, Ville Vout=
ilainen wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 28 March 2017=
 at 22:52, Nicol Bolas &lt;<a href=3D"javascript:" target=3D"_blank" gdf-ob=
fuscated-mailto=3D"0p6fwDrPBwAJ" rel=3D"nofollow" onmousedown=3D"this.href=
=3D&#39;javascript:&#39;;return true;" onclick=3D"this.href=3D&#39;javascri=
pt:&#39;;return true;">jmck...@gmail.com</a>&gt; wrote:
<br>&gt;&gt; That is far beyond something from a wording perspective; it&#3=
9;s the
<br>&gt;&gt; fundamental issue
<br>&gt;&gt; why destructive move proposals thus far haven&#39;t been accep=
ted. The
<br>&gt;&gt; motivation of
<br>&gt;&gt; a destructive move has not been strong enough to add a new way=
 of
<br>&gt;&gt; ending the lifetime
<br>&gt;&gt; of an object. Let alone starting to talk about a new kind of a=
 special
<br>&gt;&gt; member function,
<br>&gt;&gt; or new kinds of type classifications.
<br>&gt; So the already explained performance improvements are not strong e=
nough of a
<br>&gt; motivation? I really don&#39;t understand that kind of thinking. W=
hat exactly do
<br>
<br>The *&quot;explained&quot;* performance benefits? Show us hard numbers,=
 and show
<br>that similar
<br>improvements aren&#39;t achievable without fundamental changes to the
<br>object and memory model.
<br></blockquote><div><br>No &quot;fundamental changes to the object and me=
mory model&quot; are being proposed. At its most minimal, there is a single=
 function which has a part of its definition that it ends the lifetime of o=
ne of its parameters.<br><br>Ending the lifetime of an object without calli=
ng the destructor is legal. Right now, in the memory model as it currently =
stands: [basic.life]/5<br><br>&gt; For an object of a class type with a non=
-trivial destructor, the program is not required to call the destructor exp=
licitly before the storage which the object occupies is reused or released;=
 however, if there is no explicit call to the destructor or if a delete-exp=
ression (8.3.5) is not used to release the storage, the destructor shall no=
t be implicitly called and<br>any program that depends on the side effects =
produced by the destructor has undefined behavior.<br><br>A type which is r=
elocatable/destructive-moveable is essentially saying, &quot;when invoking =
the relocation/destructive-move operation, this program does not depend on =
side effects produced by the destructor of this type.&quot; And therefore, =
the destructive move operation is able to say &quot;I&#39;m ending the life=
time of the source object(s).&quot;<br><br>The object and memory models are=
 unchanged. We&#39;re simply using what the memory model currently allows, =
in a way that other types can key off of.<br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/8e05d603-f79e-4e95-b3c6-37cfa9ce41b7%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/8e05d603-f79e-4e95-b3c6-37cfa9ce41b7=
%40isocpp.org</a>.<br />

------=_Part_15054_341767830.1490733671152--

------=_Part_15053_260405871.1490733671151--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 28 Mar 2017 23:57:06 +0300
Raw View
On 28 March 2017 at 23:41, Nicol Bolas <jmckesson@gmail.com> wrote:
>> The *"explained"* performance benefits? Show us hard numbers, and show
>> that similar
>> improvements aren't achievable without fundamental changes to the
>> object and memory model.
>
>
> No "fundamental changes to the object and memory model" are being proposed.

Save for a new kind of function that can end the lifetime of objects,
and provides a means
to transfer ownership at the same time. Sure, the underlying model
allows this, but providing
a codified mechanism for it in order to make certain kinds of
std::list implementations
faster hasn't thus far convinced enough of the committee to adopt the proposals.

> At its most minimal, there is a single function which has a part of its
> definition that it ends the lifetime of one of its parameters.

Yes, I've seen Halpern's destructive move proposals.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUYFDx%3DE5dLWhwA-Xsb2QdEdz0%2B_y-FtGHO425DwtXxHZg%40mail.gmail.com.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 28 Mar 2017 15:57:05 -0700
Raw View
On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 10:46:57 PDT Jens Maurer wrot=
e:
> On 2017-03-28 18:46, Thiago Macieira wrote:
> > Qt containers do have the ability to reallocate (we don't use
> > std::allocator).
> How do those containers deal with the lifetime issues?
>=20
> >> Also, I've seen proposals floating around to allow the allocator to
> >> inform the container of the "real" size that was allocated.  That
> >> appears to mean that any realloc() beyond that will cause a
> >> malloc + memcpy under the hood.
> >=20
> > Right, we'd like a more powerful allocation mechanism that did that, pl=
us
> > a
> > non-relocating reallocation. However, every time that was brought up, i=
t
> > seemed that we couldn't get WG14 on board, so it's unlikely to happen i=
n
> > the C library.
> >=20
> > If it won't happen in the C library, we can't have it.
>=20
> Why?  The C++ interface to allocation is "new" and "delete",
> not "malloc" and "free".

Then please implement the resizing of a memory allocation without changing =
the=20
pointer address. For example:

 void *operator new(size_t size);
 void operator delete(void *ptr);
 void resize_inplace(void *ptr, size_t newsize);

I'd like to see the implementation of that third function.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/10586912.dvAV5TdMNk%40tjmaciei-mobl1.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 28 Mar 2017 15:58:18 -0700
Raw View
On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 11:07:18 PDT Matthew Woehlke =
wrote:
> > Fourth, we have the case of triviality. A class that is trivially move
> > constructible and trivially destructible is trivially move-destructible=
.. A
> > trivial move-destruction is a memcpy and abandon, so trivial
> > move-destruction is relocation.
>=20
> Okay, ugh... what I think most of us call "relocation" you are calling
> "move-destruction". Can we please stick to "relocation" (what you call
> move-destruction) and "trivial relocation" (what you call relocation)?

Only if:

> > I don't know if we could say that a complex type with non-trivial
> > move constructor and non-trivial destructor could have trivial
> > move-destructor.
>=20
> We can, and we need to be able to do so, for unique_ptr and similar class=
es.

We can make a non-trivial type have a trivial relocation.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/1812516.hEUsYuWoE9%40tjmaciei-mobl1.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 28 Mar 2017 21:33:21 -0700
Raw View
On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 11:10:55 PDT Nicol Bolas wrot=
e:
> > First, there's the destructive move, an operation that ties both a move
> > construction of the destination with the destruction of the source. It
> > needs
> > to be a new function that one can add to their class. In most cases, it
> > will
> > be what the move constructor does, except that it knows the source will
> > never
> > ever be used again, so it need not leave that in a valid state.
>=20
> It's not just that it doesn't leave it in a valid state. From a wording
> perspective, this operation must *terminate* the lifetime of the old obje=
ct.
>=20
> Otherwise, the lifetime hasn't ended and the source is still a live objec=
t.

I agree.

> > Third, we have the relocation, which is a special case of move-destruct=
ion
> > that is a simple memcpy and abandon source.
>=20
> I'm not sure I agree with the need for such a back-door. It seems to me
> that, if `T` is trivially move-destructible, `move_destroy` can do this
> just fine. We shouldn't encourage people to use memcpy&drop instead of th=
e
> equally-performance-friendly alternative.

I would agree, except for the realloc case below.

> > The reason I'm separating the concerns here is that a type could implem=
ent
> > a
> > move-destruction which is not simple memcpy + drop.
>=20
> Here's the question I have for that: why implement move-destruction at al=
l
> in that case? If your type needs to do actual work in its move-destructor=
,
> why bother? The `move_destroy` call is going to have to loop over `count`
> and call your move-destruction function. How will that perform better tha=
n
> calling the move constructor, followed by the destructor?

I just wasn't ruling it out. Let's take for example:

struct S
{
 struct Private {
  struct S *q;
 };
 Private *d;
 S();  // out-of-line

 S(S &&other) : d(other.d)
 {
  d.q =3D this;
  other.d =3D nullptr;
 }
 ~S() { delete d; }
};

In this case, the move-destruction could be more efficient than move follow=
ed by=20
destruction, especially if the destructor were out-of-line.

In fact, in any case where either the move constructor or the destructor is=
=20
out-of-line, a move-destructor would be more efficient.

> Also, move-destruction cannot *ever* throw.

I'd say it can throw as much as a destructor can.

> It seems to me that there are really only two types:
> trivially-move-destructible types and types that cannot be move-destructe=
d.
> The third type, non-trivial move destruction, seems rather pointless.

Maybe pointless, but like I said, I wasn't ruling them out.

> > Finally, there's realloc() and lifetimes. I want to apply realloc() to
> > anything that is relocatable, whether it has trivial constructor and
> > destructor or not.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/2321956.rJFP5n1JL8%40tjmaciei-mobl1.

.


Author: Marc Mutz <marc.mutz@kdab.com>
Date: Wed, 29 Mar 2017 11:32:27 +0200
Raw View
On Tuesday 28 March 2017 20:40:34 Matthew Woehlke wrote:
> On 2017-03-28 14:10, Nicol Bolas wrote:
> > On 2017-03-28 13:50, Thiago Macieira wrote:
> >> The reason I'm separating the concerns here is that a type could
> >> implement  a move-destruction which is not simple memcpy + drop.
> >
> >
> >
> > Here's the question I have for that: why implement move-destruction at
> > all  in that case? If your type needs to do actual work in its
> > move-destructor, why bother? The `move_destroy` call is going to have to
> > loop over `count` and call your move-destruction function. How will that
> > perform better than calling the move constructor, followed by the
> > destructor?
>
> Let's say I have a type that has pointer members that relate to `this`.
> It is not trivially move-destructible since it needs to fix up these
> pointers when it is relocated. But it might need to do complicated
> things in its move ctor and/or dtor.
>
> Rare? Probably, but what's the value in precluding the possibility?

These classes naturally come up if your pimpl'd class has a back pointer to
the public class. It still might be faster to just fix up the back link in the
private class than to perform a move + dtor call, in particular because
compilers suck at removing dtor calls, the more so if any non-inline function
is called in between.

--
Marc Mutz <marc.mutz@kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
Tel: +49-30-521325470
KDAB - The Qt, C++ and OpenGL Experts

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Wed, 29 Mar 2017 14:19:19 -0400
Raw View
On 2017-03-28 16:20, Ville Voutilainen wrote:
> On 28 March 2017 at 22:52, Nicol Bolas wrote:
>> So the already explained performance improvements are not strong enough =
of a
>> motivation? I really don't understand that kind of thinking. What exactl=
y do
>=20
> The *"explained"* performance benefits? Show us hard numbers,

Okay.

I created a type that contains a unique_ptr<string>, which is always
initialized to "hello, world!". The copy ctor, dtor, and assignment
operator were all defaulted. I then inserted 1000 of these into a
modified=C2=B9 QVector in three trials; one with the move ctor suppressed,
one with a defaulted move ctor, and one with Q_MOVABLE_TYPE. I also ran
both sets with -O0 and -O3.

Results:

            -O0    -O3
  copy      5.53  10.37
  move      5.40   8.53
  relocate  4.43   8.24

(The -O0 numbers are smaller because I ran 5x as many iterations for the
-O3 case.)

I'm actually surprised the difference is so small, considering the
difference in code paths:

  // relocate case
  memcpy(dst, srcBegin, srcEnd - srcBegin);
  dst +=3D srcEnd - srcBegin;
  if (false) ...

  // move case
  while (srcBegin !=3D srcEnd)
    new (dst++) T(std::move(*srcBegin++));

This suggests that either a) memcpy is slower than we think it is, or b)
the compiler is able to optimize the move case better than we think it
can. (Note: I have not attempted to examine the generated machine
instructions for any of these tests.)

Interestingly, if I increase the item count to 100k, the difference
between the move and relocate cases becomes noise.

(=C2=B9 Stock QVector does not use move construction during resizing; I use=
d
a local copy that I modified to do so.)

Another interesting test I have not done would be sorting a list when
the swap operation can be implemented either as relocation or "the hard
way". Relocation would especially win if

> and show that similar improvements aren't achievable without
> fundamental changes to the object and memory model.

I can't do that; you're asking us to prove a negative, which any
educated person knows is next to impossible. I think the onus should
instead be on the nay-sayers to demonstrate a plausible way of achieving
similar benefits *without* relocation.

--=20
Matthew

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/58DBFAA7.6080900%40gmail.com.

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Wed, 29 Mar 2017 21:37:32 +0300
Raw View
On 29 March 2017 at 21:19, Matthew Woehlke <mwoehlke.floss@gmail.com> wrote:
> This suggests that either a) memcpy is slower than we think it is, or b)
> the compiler is able to optimize the move case better than we think it
> can. (Note: I have not attempted to examine the generated machine
> instructions for any of these tests.)

Perhaps a proposal author should.

> Interestingly, if I increase the item count to 100k, the difference
> between the move and relocate cases becomes noise.

Which was, I think, a claim made by some opponents of destructive move.

>> and show that similar improvements aren't achievable without
>> fundamental changes to the object and memory model.
>
> I can't do that; you're asking us to prove a negative, which any
> educated person knows is next to impossible. I think the onus should
> instead be on the nay-sayers to demonstrate a plausible way of achieving
> similar benefits *without* relocation.

You can think whatever you want, but the onus is on a proposal author
to convince
the committee to accept the proposal, not the other way around. I'm
also not asking you
to prove a negative; I'm hinting at exploring whether compilers can be
made smarter,
and what the effort difference of that compared to teaching compilers
new lifetime rules is.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUZrHFtpci6%3D5A_M77yFyQCj9MVHNi_bumzC5oxGxd-C0A%40mail.gmail.com.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 29 Mar 2017 12:28:18 -0700 (PDT)
Raw View
------=_Part_1939_526081875.1490815698528
Content-Type: multipart/alternative;
 boundary="----=_Part_1940_1868821515.1490815698528"

------=_Part_1940_1868821515.1490815698528
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On Wednesday, March 29, 2017 at 2:19:22 PM UTC-4, Matthew Woehlke wrote:
>
> On 2017-03-28 16:20, Ville Voutilainen wrote:=20
> > On 28 March 2017 at 22:52, Nicol Bolas wrote:=20
> >> So the already explained performance improvements are not strong enoug=
h=20
> of a=20
> >> motivation? I really don't understand that kind of thinking. What=20
> exactly do=20
> >=20
> > The *"explained"* performance benefits? Show us hard numbers,=20
>
> Okay.=20
>
> I created a type that contains a unique_ptr<string>, which is always=20
> initialized to "hello, world!". The copy ctor, dtor, and assignment=20
> operator were all defaulted. I then inserted 1000 of these into a=20
> modified=C2=B9 QVector in three trials; one with the move ctor suppressed=
,=20
> one with a defaulted move ctor, and one with Q_MOVABLE_TYPE. I also ran=
=20
> both sets with -O0 and -O3.=20
>
> Results:=20
>
>             -O0    -O3=20
>   copy      5.53  10.37=20
>   move      5.40   8.53=20
>   relocate  4.43   8.24=20
>
> (The -O0 numbers are smaller because I ran 5x as many iterations for the=
=20
> -O3 case.)=20
>
> I'm actually surprised the difference is so small, considering the=20
> difference in code paths:=20
>
>   // relocate case=20
>   memcpy(dst, srcBegin, srcEnd - srcBegin);=20
>   dst +=3D srcEnd - srcBegin;=20
>   if (false) ...=20
>
>   // move case=20
>   while (srcBegin !=3D srcEnd)=20
>     new (dst++) T(std::move(*srcBegin++));=20
>
> This suggests that either a) memcpy is slower than we think it is, or b)=
=20
> the compiler is able to optimize the move case better than we think it=20
> can. (Note: I have not attempted to examine the generated machine=20
> instructions for any of these tests.)=20
>
> Interestingly, if I increase the item count to 100k, the difference=20
> between the move and relocate cases becomes noise.
>

I think a better case would be for a type which is *not* trivially=20
copyable. I expect compilers to be able to optimize away a loop over a=20
trivial destructor. It's a lot harder for them to optimize away a loop over=
=20
a non-trivial destructor.

Compare the difference between a `vector<T*>` and `vector<unique_ptr<T>>`.=
=20
The former will have the same move performance characteristics as a=20
relocatable `unique_ptr` would.

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/c24f74b4-5df5-49f0-a3fa-8747411b6c45%40isocpp.or=
g.

------=_Part_1940_1868821515.1490815698528
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, March 29, 2017 at 2:19:22 PM UTC-4, Matthew =
Woehlke wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 2017-03-28 16=
:20, Ville Voutilainen wrote:
<br>&gt; On 28 March 2017 at 22:52, Nicol Bolas wrote:
<br>&gt;&gt; So the already explained performance improvements are not stro=
ng enough of a
<br>&gt;&gt; motivation? I really don&#39;t understand that kind of thinkin=
g. What exactly do
<br>&gt;=20
<br>&gt; The *&quot;explained&quot;* performance benefits? Show us hard num=
bers,
<br>
<br>Okay.
<br>
<br>I created a type that contains a unique_ptr&lt;string&gt;, which is alw=
ays
<br>initialized to &quot;hello, world!&quot;. The copy ctor, dtor, and assi=
gnment
<br>operator were all defaulted. I then inserted 1000 of these into a
<br>modified=C2=B9 QVector in three trials; one with the move ctor suppress=
ed,
<br>one with a defaulted move ctor, and one with Q_MOVABLE_TYPE. I also ran
<br>both sets with -O0 and -O3.
<br>
<br>Results:
<br>
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 -O0 =C2=A0 =C2=A0-O3
<br>=C2=A0 copy =C2=A0 =C2=A0 =C2=A05.53 =C2=A010.37
<br>=C2=A0 move =C2=A0 =C2=A0 =C2=A05.40 =C2=A0 8.53
<br>=C2=A0 relocate =C2=A04.43 =C2=A0 8.24
<br>
<br>(The -O0 numbers are smaller because I ran 5x as many iterations for th=
e
<br>-O3 case.)
<br>
<br>I&#39;m actually surprised the difference is so small, considering the
<br>difference in code paths:
<br>
<br>=C2=A0 // relocate case
<br>=C2=A0 memcpy(dst, srcBegin, srcEnd - srcBegin);
<br>=C2=A0 dst +=3D srcEnd - srcBegin;
<br>=C2=A0 if (false) ...
<br>
<br>=C2=A0 // move case
<br>=C2=A0 while (srcBegin !=3D srcEnd)
<br>=C2=A0 =C2=A0 new (dst++) T(std::move(*srcBegin++));
<br>
<br>This suggests that either a) memcpy is slower than we think it is, or b=
)
<br>the compiler is able to optimize the move case better than we think it
<br>can. (Note: I have not attempted to examine the generated machine
<br>instructions for any of these tests.)
<br>
<br>Interestingly, if I increase the item count to 100k, the difference
<br>between the move and relocate cases becomes noise.<br></blockquote><div=
><br>I think a better case would be for a type which is <i>not</i> triviall=
y copyable. I expect compilers to be able to optimize away a loop over a tr=
ivial destructor. It&#39;s a lot harder for them to optimize away a loop ov=
er a non-trivial destructor.<br><br>Compare the difference between a `vecto=
r&lt;T*&gt;` and `vector&lt;unique_ptr&lt;T&gt;&gt;`. The former will have =
the same move performance characteristics as a relocatable `unique_ptr` wou=
ld.<br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/c24f74b4-5df5-49f0-a3fa-8747411b6c45%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/c24f74b4-5df5-49f0-a3fa-8747411b6c45=
%40isocpp.org</a>.<br />

------=_Part_1940_1868821515.1490815698528--

------=_Part_1939_526081875.1490815698528--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 29 Mar 2017 12:41:56 -0700 (PDT)
Raw View
------=_Part_2161_373411168.1490816516616
Content-Type: multipart/alternative;
 boundary="----=_Part_2162_769467618.1490816516616"

------=_Part_2162_769467618.1490816516616
Content-Type: text/plain; charset=UTF-8

On Wednesday, March 29, 2017 at 2:37:34 PM UTC-4, Ville Voutilainen wrote:
>
> On 29 March 2017 at 21:19, Matthew Woehlke <mwoehlk...@gmail.com
> <javascript:>> wrote:
> > This suggests that either a) memcpy is slower than we think it is, or b)
> > the compiler is able to optimize the move case better than we think it
> > can. (Note: I have not attempted to examine the generated machine
> > instructions for any of these tests.)
>
> Perhaps a proposal author should.
>
> > Interestingly, if I increase the item count to 100k, the difference
> > between the move and relocate cases becomes noise.
>
> Which was, I think, a claim made by some opponents of destructive move.
>
> >> and show that similar improvements aren't achievable without
> >> fundamental changes to the object and memory model.
> >
> > I can't do that; you're asking us to prove a negative, which any
> > educated person knows is next to impossible. I think the onus should
> > instead be on the nay-sayers to demonstrate a plausible way of achieving
> > similar benefits *without* relocation.
>
> You can think whatever you want, but the onus is on a proposal author
> to convince
> the committee to accept the proposal, not the other way around.


Tell me: did the various rvalue-reference proposals have to go through so
much scrutiny? Did their authors have to prove that compilers couldn't find
ways to detect "movement" type operations without explicit syntax and
object models for it? What about the proposals that led to the creation of
the TriviallyCopyable concept; did the authors of those have to *prove*
that compilers would be incapable of achieving performance equivalent to a
`memcpy` without letting us actually `memcpy` them?

There have been plenty of proposals that have been accepted that *don't*
rise to such a level of scrutiny. Why is this one so special?

And most importantly of all, why does it matter? What is the reason for
being against explicitly providing users the ability to do such things,
when the alternative is essentially *hoping* that compilers can optimize
the cruft away?

I don't understand the logic of declaring QoI to be an effective strategy
of making C++ fast.

I'm
> also not asking you
> to prove a negative; I'm hinting at exploring whether compilers can be
> made smarter,
> and what the effort difference of that compared to teaching compilers
> new lifetime rules is.
>

But there is no effort in teaching compilers "new lifetime rules," since
there are no "new lifetime rules". Consider the following function:

void func(T *src, size_t count = 1)
{
  new(src) unsigned char[count * sizeof(T)];
}

This function ends the lifetime of all objects stored between `src` and
`src + count`. The compiler must already be able to handle this, because
that's part of the standard right now.

So a function that ends the lifetime of one of its arguments without
calling the destructor is not new.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/9d00d388-cbcd-409c-8c22-af92fcaaa539%40isocpp.org.

------=_Part_2162_769467618.1490816516616
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, March 29, 2017 at 2:37:34 PM UTC-4, Ville Vo=
utilainen wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 29 March 20=
17 at 21:19, Matthew Woehlke &lt;<a href=3D"javascript:" target=3D"_blank" =
gdf-obfuscated-mailto=3D"5HCoEzIYCAAJ" rel=3D"nofollow" onmousedown=3D"this=
..href=3D&#39;javascript:&#39;;return true;" onclick=3D"this.href=3D&#39;jav=
ascript:&#39;;return true;">mwoehlk...@gmail.com</a>&gt; wrote:
<br>&gt; This suggests that either a) memcpy is slower than we think it is,=
 or b)
<br>&gt; the compiler is able to optimize the move case better than we thin=
k it
<br>&gt; can. (Note: I have not attempted to examine the generated machine
<br>&gt; instructions for any of these tests.)
<br>
<br>Perhaps a proposal author should.
<br>
<br>&gt; Interestingly, if I increase the item count to 100k, the differenc=
e
<br>&gt; between the move and relocate cases becomes noise.
<br>
<br>Which was, I think, a claim made by some opponents of destructive move.
<br>
<br>&gt;&gt; and show that similar improvements aren&#39;t achievable witho=
ut
<br>&gt;&gt; fundamental changes to the object and memory model.
<br>&gt;
<br>&gt; I can&#39;t do that; you&#39;re asking us to prove a negative, whi=
ch any
<br>&gt; educated person knows is next to impossible. I think the onus shou=
ld
<br>&gt; instead be on the nay-sayers to demonstrate a plausible way of ach=
ieving
<br>&gt; similar benefits *without* relocation.
<br>
<br>You can think whatever you want, but the onus is on a proposal author
<br>to convince
<br>the committee to accept the proposal, not the other way around.</blockq=
uote><div><br>Tell me: did the various rvalue-reference proposals have to g=
o through so much scrutiny? Did their authors have to prove that compilers =
couldn&#39;t find ways to detect &quot;movement&quot; type operations witho=
ut explicit syntax and object models for it? What about the proposals that =
led to the creation of the TriviallyCopyable concept; did the authors of th=
ose have to <i>prove</i> that compilers would be incapable of achieving per=
formance equivalent to a `memcpy` without letting us actually `memcpy` them=
?<br><br>There have been plenty of proposals that have been accepted that <=
i>don&#39;t</i> rise to such a level of scrutiny. Why is this one so specia=
l?<br><br>And most importantly of all, why does it matter? What is the reas=
on for being against explicitly providing users the ability to do such thin=
gs, when the alternative is essentially <i>hoping</i> that compilers can op=
timize the cruft away?<br><br>I don&#39;t understand the logic of declaring=
 QoI to be an effective strategy of making C++ fast.<br><br></div><blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
 1px #ccc solid;padding-left: 1ex;">I&#39;m
<br>also not asking you
<br>to prove a negative; I&#39;m hinting at exploring whether compilers can=
 be
<br>made smarter,
<br>and what the effort difference of that compared to teaching compilers
<br>new lifetime rules is.<br></blockquote><div><br>But there is no effort =
in teaching compilers &quot;new lifetime rules,&quot; since there are no &q=
uot;new lifetime rules&quot;. Consider the following function:<br><br><div =
style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, =
187); border-style: solid; border-width: 1px; overflow-wrap: break-word;" c=
lass=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subprettypri=
nt"><span style=3D"color: #008;" class=3D"styled-by-prettify">void</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> func</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">T </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">*</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">src</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> size_t count </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">1</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">new</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">src</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">u=
nsigned</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 styl=
e=3D"color: #000;" class=3D"styled-by-prettify">count </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">*</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">sizeof</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">T</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">)];</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</span=
></div></code></div><br>This function ends the lifetime of all objects stor=
ed between `src` and `src + count`. The compiler must already be able to ha=
ndle this, because that&#39;s part of the standard right now.<br><br>So a f=
unction that ends the lifetime of one of its arguments without calling the =
destructor is not new.<br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/9d00d388-cbcd-409c-8c22-af92fcaaa539%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/9d00d388-cbcd-409c-8c22-af92fcaaa539=
%40isocpp.org</a>.<br />

------=_Part_2162_769467618.1490816516616--

------=_Part_2161_373411168.1490816516616--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Wed, 29 Mar 2017 22:16:02 +0200
Raw View
On 03/29/2017 09:41 PM, Nicol Bolas wrote:
> Tell me: did the various rvalue-reference proposals have to go through so much scrutiny?

I'm not sure about "various", but the one that ended up in the standard
did get its share of scrutiny.

>  Did their authors have to prove that compilers couldn't find ways to detect "movement" type operations without explicit syntax and object models for it?

For an example such as std::vector<std::string>, I believe
we had performance charts and, as far as I remember, it was
clear that we would need to require the compiler to fold
allocations and deallocations of dynamic memory, which is
(in general) and non-analyzed external function call, absent
LTO or similar.

> What about the proposals that led to the creation of the TriviallyCopyable concept; did the authors of those have to /prove/ that compilers would be incapable of achieving performance equivalent to a `memcpy` without letting us actually `memcpy` them?

I don't know what you mean here.  From a standards perspective, all
that "trivially copyable" does is enable [basic.types] p2 and p3;
note that these paragraphs are carefully crafted to refer to
existing objects (presumably within their lifetimes), whose values
are then modified using memcpy.  That doesn't really help the
std::vector reallocation case.

On the implementation level, "trivially copyable" is a useful term
to indicate that copies are not observable by the user unless the
address of an object is taken (i.e. no user code is called to
perform the copy), so those types are suitable for putting into
registers or, in fact, for memcpy'ing on the implementation level.

> There have been plenty of proposals that have been accepted that /don't/ rise to such a level of scrutiny. Why is this one so special?

Because 20+ years of exposure to the C++ memory model makes us
scared as hell to try to mess with it. For example, it took us
that long to realize that std::vector (in particular the data()
member returning a pointer to an array lookalike) isn't actually
implementable with the current memory model.  See also P0137R1.

> And most importantly of all, why does it matter? What is the reason for being against explicitly providing users the ability to do such things, when the alternative is essentially /hoping/ that compilers can optimize the cruft away?

Because breaking the memory model means breaking good-looking
C++ code in unpredictable ways once the optimizers get an
understanding of the memory model update.

That is much more scary than adding yet another syntax-level
feature such as structured bindings or implicit comparisons or
even concepts.

> I don't understand the logic of declaring QoI to be an effective strategy of making C++ fast.

Because QoI is what keeps the workload for the committee manageable?

> But there is no effort in teaching compilers "new lifetime rules," since there are no "new lifetime rules". Consider the following function:

> void func(T *src, size_t count =1)
> {
>   new(src) unsigned char[count * sizeof(T)];
> }
>
> This function ends the lifetime of all objects stored between `src` and `src + count`.

Yes,
 - possibly already causing undefined behavior if those objects had a non-trivial
destructor,
 - using "new", which we already taught to the optimizers as being "special".

>   The compiler must already be able to handle this, because that's part of the standard right now.
>
> So a function that ends the lifetime of one of its arguments without calling the destructor is not new.

Sure, but is it worth the effort (for the destructive move case)?

Jens

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/58DC1602.3010303%40gmx.net.

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Wed, 29 Mar 2017 16:17:02 -0400
Raw View
On 2017-03-29 15:28, Nicol Bolas wrote:
> On Wednesday, March 29, 2017 at 2:19:22 PM UTC-4, Matthew Woehlke wrote:
>> I created a type that contains a unique_ptr<string>, which is always=20
>> initialized to "hello, world!". The copy ctor, dtor, and assignment=20
>> operator were all defaulted. I then inserted 1000 of these into a=20
>> modified=C2=B9 QVector in three trials; one with the move ctor suppresse=
d,=20
>> one with a defaulted move ctor, and one with Q_MOVABLE_TYPE. I also ran=
=20
>> both sets with -O0 and -O3.=20
>>
>> Results:=20
>>
>>             -O0    -O3=20
>>   copy      5.53  10.37=20
>>   move      5.40   8.53=20
>>   relocate  4.43   8.24=20
>>
>> (The -O0 numbers are smaller because I ran 5x as many iterations for the=
=20
>> -O3 case.)=20
>>
>> I'm actually surprised the difference is so small [...]
>=20
> I think a better case would be for a type which is *not* trivially=20
> copyable. I expect compilers to be able to optimize away a loop over a=20
> trivial destructor. It's a lot harder for them to optimize away a loop ov=
er=20
> a non-trivial destructor.

....but the dtor *isn't* trivial! It has to check if the pointer is null,
and free it if not. Nor is move construction trivial; it has to steal
the pointer from the moved-from unique_ptr. Apparently the compiler is
able to detect that it will always be null because the unique_ptr was
moved-from and can thus optimize away the dtor.

The only other possibility that comes to mind is that Qt is treating my
type as relocatable *without* Q_MOVABLE_TYPE if it has a move ctor...

> Compare the difference between a `vector<T*>` and `vector<unique_ptr<T>>`=
..=20
> The former will have the same move performance characteristics as a=20
> relocatable `unique_ptr` would.

Okay, that seems like a plausible test:

  vector<unique_ptr<int>   4.4
  vector<int*>             2.8

Well. Those are better numbers, anyway :-).

--=20
Matthew

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/58DC163E.7050403%40gmail.com.

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Wed, 29 Mar 2017 23:05:24 +0200
Raw View
On 03/29/2017 08:19 PM, Matthew Woehlke wrote:
> On 2017-03-28 16:20, Ville Voutilainen wrote:
>> The *"explained"* performance benefits? Show us hard numbers,
>=20
> Okay.
>=20
> I created a type that contains a unique_ptr<string>, which is always
> initialized to "hello, world!". The copy ctor, dtor, and assignment
> operator were all defaulted. I then inserted 1000 of these into a
> modified=C2=B9 QVector in three trials; one with the move ctor suppressed=
,
> one with a defaulted move ctor, and one with Q_MOVABLE_TYPE. I also ran
> both sets with -O0 and -O3.
>=20
> Results:
>=20
>             -O0    -O3
>   copy      5.53  10.37

How does "copy" work, since the type you created doesn't seem
have a copy constructor?  (At least unique_ptr doesn't.)

>   move      5.40   8.53
>   relocate  4.43   8.24

Thanks for the experiment.  On my 32-bit Intel box,

struct S {
  std::unique_ptr<std::string> p;
};

void f(S * dst, S * src, S * end)
{
  while (src !=3D end)
    new (dst++) S(std::move(*src++));
}

compiles to (inner loop shown only; gcc 6.3.0):

..L3:
        addl    $4, %eax
        testl   %edx, %edx
        je      .L4
        movl    -4(%eax), %ecx
        movl    $0, -4(%eax)
        movl    %ecx, (%edx)
..L4:
        addl    $4, %edx
        cmpl    %eax, %ebx
        jne     .L3

(I'm not sure what the null pointer check for the
destination is supposed to do here.)

Presumably, the optimizer doesn't know in this case that
dst and src won't overlap.  I've tried both "restrict" and
a local "malloc" for dst to teach the optimizer that fact,
but failed.

(Even for memcpy, the optimizer needs to assert non-overlap.)

This doesn't look far from "memcpy" and "memset", it seems to me.
All memory accesses are sequential, which greatly helps throughput
and automatic prefetch.

> Interestingly, if I increase the item count to 100k, the difference
> between the move and relocate cases becomes noise.

Yup, you're measuring RAM access latency and not much else.

> (=C2=B9 Stock QVector does not use move construction during resizing; I u=
sed
> a local copy that I modified to do so.)
>=20
> Another interesting test I have not done would be sorting a list when
> the swap operation can be implemented either as relocation or "the hard
> way". Relocation would especially win if

Sentence chopped off?

Jens

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/58DC2194.4050402%40gmx.net.

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Thu, 30 Mar 2017 00:14:10 +0300
Raw View
On 30 March 2017 at 00:05, Jens Maurer <Jens.Maurer@gmx.net> wrote:
> .L3:
>         addl    $4, %eax
>         testl   %edx, %edx
>         je      .L4
>         movl    -4(%eax), %ecx
>         movl    $0, -4(%eax)
>         movl    %ecx, (%edx)
> .L4:
>         addl    $4, %edx
>         cmpl    %eax, %ebx
>         jne     .L3
>
> (I'm not sure what the null pointer check for the
> destination is supposed to do here.)

That would be https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35878

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUbiOwCgRK07GmMRqxKGV8E4A3oVEffgZA7qTU5cR1Y7cQ%40mail.gmail.com.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Wed, 29 Mar 2017 16:05:57 -0700
Raw View
On ter=C3=A7a-feira, 28 de mar=C3=A7o de 2017 13:20:25 PDT Ville Voutilaine=
n wrote:
> The *"explained"* performance benefits? Show us hard numbers, and show
> that similar
> improvements aren't achievable without fundamental changes to the
> object and memory model.

Here are my numbers. This was also posted to the Qt development mailing lis=
t,=20
where the same discussion is happening.

Source code: http://paste.opensuse.org/83426813
[Does not compile with standard Qt, use [1]]

Without further ado, results. Analysis and conclusions below.

GCC 6.3:,CPU cycles,% of move,
copyTrivial,"7.015.001,04688",105%,
moveTrivial,"6.653.361,60938",100%,
memcpyTrivial,"5.556.582,67969",84%,
reallocTrivial,"3.209.727,01953",48%,
copyComplex,"50.938.402,71875",99%,
moveComplex,"51.306.523,56250",100%,
memcpyComplex,"40.689.058,50000",79%,
reallocComplex,"13.450.587,92188",26%,
,,,
Clang trunk:,,,
copyTrivial,"6.366.532,53906",101%,
moveTrivial,"6.284.109,14063",100%,
memcpyTrivial,"6.410.652,50000",102%,
reallocTrivial,"3.926.226,85547",62%,
copyComplex,"44.778.841,93750",84%,
moveComplex,"53.097.208,06250",100%,
memcpyComplex,"38.966.088,87500",73%,
reallocComplex,"12.701.627,09375",24%,
,,,
ICC 17:,,,
copyTrivial,"7.656.487,46094",100%,
moveTrivial,"7.688.472,17969",100%,
memcpyTrivial,"8.346.315,19531",109%,
reallocTrivial,"4.885.068,30859",64%,
copyComplex,"68.326.384,37500",91%,
moveComplex,"75.145.256,50000",100%,
memcpyComplex,"52.546.942,75000",70%,
reallocComplex,"29.427.426,37500",39%,

Analysis:

1) I've valground the application and it leaks no memory

2) the application was compiled with exceptions disabled, as we're not test=
ing=20
the exceptional code paths. This also simulates a complex type that has a=
=20
noexcept move constructor.

3) because this is using QArrayData allocation with GrowsForward, the=20
reallocation strategy does not happen on every execution. In fact, to appen=
d=20
one million items, the allocate() function is called only 59 times.

4) the benchmarks only the appending into the vector. The freeing of the=20
vector's elements at the end is not included.

5) there are four times two tests:
        copy + destroy original
        move + destroy original
        memcpy
        pure realloc
run each for
        a trivial type (int)
        a complex but relocatable type (QString)

6) the test is skewed towards realloc because there's no other memory=20
allocation, so realloc() is free to resize the memory block in-place, as it=
=20
sees fit. Tough luck for the other tests.

7) the copy and move operations for the trivial type are, as expected, with=
in=20
the noise of each other. The 5% of the spike for GCC does not appear in all=
=20
runs (the first test suffers a little due to warming up and the need to obt=
ain=20
memory from the OS).

8) the difference between copy/move and memcpy for the trivial type depend =
on=20
the compiler. I compiled using -O2, which means GCC did not use its=20
vectoriser, but Clang did (-march=3Dnative, so they used AVX2). Meanwhile, =
all=20
three called the libc memcpy function in the memcpy version, which has=20
vectorisation (in ICC's case, it called __intel_avx_rep_memcpy).

Conclusions:

A) for trivial types, the relocation provides negligible, if any, improveme=
nt,=20
as the operation is already there. But as shown, not all compilers are as=
=20
smart and may miss optimisation opportunities by its absence. The more=20
information the compiler has, the better it can generate code.

B) for non-trivial types, the relocation provides 25% or more performance=
=20
improvement (1 / 80% =3D 125%). That's probably because QString's destructo=
r is=20
actually non-negligible, as it needs to check if the data block it points t=
o=20
needs to be freed.

C) the realloc strategy is clearly the winner here, achieving up to 316%=20
improvement over today's state-of-the-art. As stated in the analysis, this=
=20
happens with only 59 allocations out of 1 million elements appended. Now,=
=20
since nothing else was allocated in this benchmark, realloc() most likely d=
id=20
not have to perform memcpy, so these numbers are not representative of all=
=20
applications, but they are possible and can even be surpassed with dedicate=
d=20
arena allocators.

[1] https://gitlab.com/thiagomacieira/qtbase (rebases often!)
--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/3298038.puGZeIFBIN%40tjmaciei-mobl1.

.


Author: Andrey Davydov <andrey.a.davydov@gmail.com>
Date: Wed, 29 Mar 2017 22:23:12 -0700 (PDT)
Raw View
------=_Part_619_1602321292.1490851392372
Content-Type: multipart/alternative;
 boundary="----=_Part_620_450350167.1490851392373"

------=_Part_620_450350167.1490851392373
Content-Type: text/plain; charset=UTF-8


>
> Perhaps a proposal author should.
>
Ok, there is my benchmark, tell me please if it contains any systematic
error.
#include <memory>
#include <vector>
#include <cstring>
#include <chrono>
#include <iostream>

template<class T>
void relocate_using_move(T * new_buffer, T * old_buffer, size_t size)
{
    for (size_t i = 0; i != size; ++i)
        new_buffer[i] = std::move_if_noexcept(old_buffer[i]);

    for (size_t i = 0; i != size; ++i)
        old_buffer[i].~T();
};

template<class T>
void relocate_using_memcpy(T * new_buffer, T * old_buffer, size_t size)
{
    using value_storage_type = std::aligned_storage_t<sizeof(T),
alignof(T)>;
    std::memcpy(new_buffer, old_buffer, size * sizeof(value_storage_type));
};

using clock_type = std::chrono::high_resolution_clock;

template<class Functor>
clock_type::duration repeat_n_times(Functor f, size_t times)
{
    auto start = clock_type::now();
    while (times --> 0)
        f();
    auto finish = clock_type::now();
    return finish - start;
}

void print(const char * message, clock_type::duration time)
{
    using namespace std::chrono;

    std::cout << message << ": " <<
duration_cast<milliseconds>(time).count() << "ms\n";
}

template<class T>
void destroy(T * buffer, size_t size)
{
    for (size_t i = 0; i != size; ++i)
        buffer[i].~T();
}

int main()
{
    using value_type = std::vector<int>;
    using value_storage_type = std::aligned_storage_t<sizeof(value_type),
alignof(value_type)>;

    const size_t N = 100000;

    std::unique_ptr<value_storage_type[]> buf1(new value_storage_type[N]);
    std::unique_ptr<value_storage_type[]> buf2(new value_storage_type[N]);

    for (size_t i = 0; i != N; ++i)
        new(&buf1[i]) value_type(10);

    const auto buf_ptr1 = reinterpret_cast<value_type *>(buf1.get());
    const auto buf_ptr2 = reinterpret_cast<value_type *>(buf2.get());

    const size_t invocations_num = 10;

    print("relocate using move  ", repeat_n_times([&] () {
        relocate_using_move(buf_ptr2, buf_ptr1, N);
        relocate_using_move(buf_ptr1, buf_ptr2, N);
    }, 10));
    print("relocate using memcpy", repeat_n_times([&] () {
        relocate_using_memcpy(buf_ptr2, buf_ptr1, N);
        relocate_using_memcpy(buf_ptr1, buf_ptr2, N);
    }, 10));

    destroy(buf_ptr1, N);
}
Results for `gcc -O2`:
relocate using move  : 18ms
relocate using memcpy: 4ms
Results for `gcc -O3`:
relocate using move  : 15ms
relocate using memcpy: 4ms

System information:
gcc version 6.3.1
Linux 4.9.11
Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/d159b197-0f0a-4ab4-bc67-71aff60e2410%40isocpp.org.

------=_Part_620_450350167.1490851392373
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;">Perhaps a pro=
posal author should.
<br></blockquote><div>Ok, there is my benchmark, tell me please if it conta=
ins any systematic error.<br></div><div><div class=3D"prettyprint" style=3D=
"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bo=
rder-style: solid; border-width: 1px; word-wrap: break-word;"><code class=
=3D"prettyprint"><div class=3D"subprettyprint"><span class=3D"styled-by-pre=
ttify"><div class=3D"subprettyprint"><font color=3D"#000000">#include &lt;m=
emory&gt;</font></div><div class=3D"subprettyprint"><font color=3D"#000000"=
>#include &lt;vector&gt;</font></div><div class=3D"subprettyprint"><font co=
lor=3D"#000000">#include &lt;cstring&gt;</font></div><div class=3D"subprett=
yprint"><font color=3D"#000000">#include &lt;chrono&gt;</font></div><div cl=
ass=3D"subprettyprint"><font color=3D"#000000">#include &lt;iostream&gt;</f=
ont></div><div class=3D"subprettyprint"><font color=3D"#000000"><br></font>=
</div><div class=3D"subprettyprint"><font color=3D"#000000">template&lt;cla=
ss T&gt;</font></div><div class=3D"subprettyprint"><font color=3D"#000000">=
void relocate_using_move(T * new_buffer, T * old_buffer, size_t size)</font=
></div><div class=3D"subprettyprint"><font color=3D"#000000">{</font></div>=
<div class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 for (si=
ze_t i =3D 0; i !=3D size; ++i)</font></div><div class=3D"subprettyprint"><=
font color=3D"#000000">=C2=A0 =C2=A0 =C2=A0 =C2=A0 new_buffer[i] =3D std::m=
ove_if_noexcept(old_buffer[i]);</font></div><div class=3D"subprettyprint"><=
font color=3D"#000000"><br></font></div><div class=3D"subprettyprint"><font=
 color=3D"#000000">=C2=A0 =C2=A0 for (size_t i =3D 0; i !=3D size; ++i)</fo=
nt></div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 old_buffer[i].~T();</font></div><div class=3D"subprettypr=
int"><font color=3D"#000000">};</font></div><div class=3D"subprettyprint"><=
font color=3D"#000000"><br></font></div><div class=3D"subprettyprint"><font=
 color=3D"#000000">template&lt;class T&gt;</font></div><div class=3D"subpre=
ttyprint"><font color=3D"#000000">void relocate_using_memcpy(T * new_buffer=
, T * old_buffer, size_t size)</font></div><div class=3D"subprettyprint"><f=
ont color=3D"#000000">{</font></div><div class=3D"subprettyprint"><font col=
or=3D"#000000">=C2=A0 =C2=A0 using value_storage_type =3D std::aligned_stor=
age_t&lt;sizeof(T), alignof(T)&gt;;=C2=A0</font></div><div class=3D"subpret=
typrint"><font color=3D"#000000">=C2=A0 =C2=A0 std::memcpy(new_buffer, old_=
buffer, size * sizeof(value_storage_type));</font></div><div class=3D"subpr=
ettyprint"><font color=3D"#000000">};</font></div><div class=3D"subprettypr=
int"><font color=3D"#000000"><br></font></div><div class=3D"subprettyprint"=
><font color=3D"#000000">using clock_type =3D std::chrono::high_resolution_=
clock;</font></div><div class=3D"subprettyprint"><font color=3D"#000000"><b=
r></font></div><div class=3D"subprettyprint"><font color=3D"#000000">templa=
te&lt;class Functor&gt;</font></div><div class=3D"subprettyprint"><font col=
or=3D"#000000">clock_type::duration repeat_n_times(Functor f, size_t times)=
</font></div><div class=3D"subprettyprint"><font color=3D"#000000">{</font>=
</div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 a=
uto start =3D clock_type::now();</font></div><div class=3D"subprettyprint">=
<font color=3D"#000000">=C2=A0 =C2=A0 while (times --&gt; 0)</font></div><d=
iv class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 f();</font></div><div class=3D"subprettyprint"><font color=3D"#00000=
0">=C2=A0 =C2=A0 auto finish =3D clock_type::now();</font></div><div class=
=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 return finish - s=
tart;</font></div><div class=3D"subprettyprint"><font color=3D"#000000">}</=
font></div><div class=3D"subprettyprint"><font color=3D"#000000"><br></font=
></div><div class=3D"subprettyprint"><font color=3D"#000000">void print(con=
st char * message, clock_type::duration time)</font></div><div class=3D"sub=
prettyprint"><font color=3D"#000000">{</font></div><div class=3D"subprettyp=
rint"><font color=3D"#000000">=C2=A0 =C2=A0 using namespace std::chrono;</f=
ont></div><div class=3D"subprettyprint"><font color=3D"#000000"><br></font>=
</div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 s=
td::cout &lt;&lt; message &lt;&lt; &quot;: &quot; &lt;&lt; duration_cast&lt=
;milliseconds&gt;(time).count() &lt;&lt; &quot;ms\n&quot;;</font></div><div=
 class=3D"subprettyprint"><font color=3D"#000000">}</font></div><div class=
=3D"subprettyprint"><font color=3D"#000000"><br></font></div><div class=3D"=
subprettyprint"><font color=3D"#000000">template&lt;class T&gt;</font></div=
><div class=3D"subprettyprint"><font color=3D"#000000">void destroy(T * buf=
fer, size_t size)</font></div><div class=3D"subprettyprint"><font color=3D"=
#000000">{</font></div><div class=3D"subprettyprint"><font color=3D"#000000=
">=C2=A0 =C2=A0 for (size_t i =3D 0; i !=3D size; ++i)</font></div><div cla=
ss=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 =C2=A0 =C2=A0 b=
uffer[i].~T();</font></div><div class=3D"subprettyprint"><font color=3D"#00=
0000">}</font></div><div class=3D"subprettyprint"><font color=3D"#000000"><=
br></font></div><div class=3D"subprettyprint"><font color=3D"#000000">int m=
ain()</font></div><div class=3D"subprettyprint"><font color=3D"#000000">{</=
font></div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=
=A0 using value_type =3D std::vector&lt;int&gt;;</font></div><div class=3D"=
subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 using value_storage_t=
ype =3D std::aligned_storage_t&lt;sizeof(value_type), alignof(value_type)&g=
t;;</font></div><div class=3D"subprettyprint"><font color=3D"#000000"><br><=
/font></div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =
=C2=A0 const size_t N =3D 100000;</font></div><div class=3D"subprettyprint"=
><font color=3D"#000000"><br></font></div><div class=3D"subprettyprint"><fo=
nt color=3D"#000000">=C2=A0 =C2=A0 std::unique_ptr&lt;value_storage_type[]&=
gt; buf1(new value_storage_type[N]);</font></div><div class=3D"subprettypri=
nt"><font color=3D"#000000">=C2=A0 =C2=A0 std::unique_ptr&lt;value_storage_=
type[]&gt; buf2(new value_storage_type[N]);</font></div><div class=3D"subpr=
ettyprint"><font color=3D"#000000"><br></font></div><div class=3D"subpretty=
print"><font color=3D"#000000">=C2=A0 =C2=A0 for (size_t i =3D 0; i !=3D N;=
 ++i)</font></div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 new(&amp;buf1[i]) value_type(10);</font></div><div=
 class=3D"subprettyprint"><font color=3D"#000000"><br></font></div><div cla=
ss=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 const auto buf_=
ptr1 =3D reinterpret_cast&lt;value_type *&gt;(buf1.get());</font></div><div=
 class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 const auto =
buf_ptr2 =3D reinterpret_cast&lt;value_type *&gt;(buf2.get());</font></div>=
<div class=3D"subprettyprint"><font color=3D"#000000"><br></font></div><div=
 class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0 const size_=
t invocations_num =3D 10;</font></div><div class=3D"subprettyprint"><font c=
olor=3D"#000000"><br></font></div><div class=3D"subprettyprint"><font color=
=3D"#000000">=C2=A0 =C2=A0 print(&quot;relocate using move =C2=A0&quot;, re=
peat_n_times([&amp;] () {</font></div><div class=3D"subprettyprint"><font c=
olor=3D"#000000">=C2=A0 =C2=A0 =C2=A0 =C2=A0 relocate_using_move(buf_ptr2, =
buf_ptr1, N);</font></div><div class=3D"subprettyprint"><font color=3D"#000=
000">=C2=A0 =C2=A0 =C2=A0 =C2=A0 relocate_using_move(buf_ptr1, buf_ptr2, N)=
;</font></div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =
=C2=A0 }, 10));</font></div><div class=3D"subprettyprint"><font color=3D"#0=
00000">=C2=A0 =C2=A0 print(&quot;relocate using memcpy&quot;, repeat_n_time=
s([&amp;] () {</font></div><div class=3D"subprettyprint"><font color=3D"#00=
0000">=C2=A0 =C2=A0 =C2=A0 =C2=A0 relocate_using_memcpy(buf_ptr2, buf_ptr1,=
 N);</font></div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 relocate_using_memcpy(buf_ptr1, buf_ptr2, N);</fon=
t></div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=A0 =C2=A0=
 }, 10));</font></div><div class=3D"subprettyprint"><font color=3D"#000000"=
><br></font></div><div class=3D"subprettyprint"><font color=3D"#000000">=C2=
=A0 =C2=A0 destroy(buf_ptr1, N);</font></div><div class=3D"subprettyprint">=
<font color=3D"#000000">}</font></div></span></div></code></div>Results for=
 `gcc -O2`:</div><div><span style=3D"font-family:monospace"><span style=3D"=
color: rgb(0, 0, 0);">relocate using move =C2=A0: 18ms
</span><br>relocate using memcpy: 4ms<br></span><div>Results for `gcc -O3`:=
</div><div><span style=3D"font-family: monospace;"><span style=3D"color: rg=
b(0, 0, 0);">relocate using move =C2=A0: 15ms=C2=A0</span><br>relocate usin=
g memcpy: 4ms<br></span></div></div><div><span style=3D"font-family: monosp=
ace;"><br></span></div><div><span style=3D"font-family: monospace;">System =
information:</span></div><div><span style=3D"font-family:monospace"><span s=
tyle=3D"color: rgb(0, 0, 0);">gcc version 6.3.1</span><br></span></div><div=
><span style=3D"font-family:monospace"><span style=3D"color: rgb(0, 0, 0);"=
>Linux 4.9.11</span><br></span></div><div><span style=3D"font-family:monosp=
ace"><span style=3D"color: rgb(0, 0, 0);">Intel(R) Core(TM) i7-3770 CPU @ 3=
..40GHz</span><br></span></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/d159b197-0f0a-4ab4-bc67-71aff60e2410%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d159b197-0f0a-4ab4-bc67-71aff60e2410=
%40isocpp.org</a>.<br />

------=_Part_620_450350167.1490851392373--

------=_Part_619_1602321292.1490851392372--

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Thu, 30 Mar 2017 10:12:03 -0400
Raw View
On 2017-03-29 17:05, Jens Maurer wrote:
> On 03/29/2017 08:19 PM, Matthew Woehlke wrote:
>> I created a type that contains a unique_ptr<string>, which is always
>> initialized to "hello, world!". The copy ctor, dtor, and assignment
>> operator were all defaulted. I then inserted 1000 of these into a
>> modified=C2=B9 QVector in three trials; one with the move ctor suppresse=
d,
>> one with a defaulted move ctor, and one with Q_MOVABLE_TYPE. I also ran
>> both sets with -O0 and -O3.
>>
>> Results:
>>
>>             -O0    -O3
>>   copy      5.53  10.37
>=20
> How does "copy" work, since the type you created doesn't seem
> have a copy constructor?  (At least unique_ptr doesn't.)

Right; sorry. My type had a reasonable but not defaulted copy ctor:

  item(item const& other)
    : data{std::make_unique<std::string>(*other.data)}
    {}

(I was originally using plain old `int` as the data type; the results
were comparable to using `std::string`. The original intent was to have
a type that acted like a simple CoW value type.)

>> Another interesting test I have not done would be sorting a list when
>> the swap operation can be implemented either as relocation or "the hard
>> way". Relocation would especially win if
>=20
> Sentence chopped off?

I guess... alas, now I can't remember what I meant to say :-).

--=20
Matthew

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/58DD1233.2050209%40gmail.com.

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Thu, 30 Mar 2017 17:20:26 +0200
Raw View
On 03/29/2017 11:05 PM, Jens Maurer wrote:
> void f(S * dst, S * src, S * end)
> {
>   while (src != end)
>     new (dst++) S(std::move(*src++));
> }
>
> compiles to (inner loop shown only; gcc 6.3.0):
>
> .L3:
>         addl    $4, %eax
>         testl   %edx, %edx
>         je      .L4
>         movl    -4(%eax), %ecx
>         movl    $0, -4(%eax)
>         movl    %ecx, (%edx)
> .L4:
>         addl    $4, %edx
>         cmpl    %eax, %ebx
>         jne     .L3

Update with calling the destructor interleaved:

#define __restrict__
void f(S * __restrict__ dst, S * __restrict__ src, S * end)
{
  while (src != end) {
    new (dst++) S(std::move(*src));
    (*src).~S();
    ++src;
  }
}

..L12:
        testl   %esi, %esi
        je      .L3
        movl    (%ebx), %eax
        movl    $0, (%ebx)
        movl    %eax, (%esi)
..L3:
        movl    (%ebx), %edi
        testl   %edi, %edi
        je      .L4
        /* destructor of std::string */
..L4:
        addl    $4, %ebx
        addl    $4, %esi
        cmpl    %ebx, %ebp
        jne     .L12

Again, the point here is that the compiler doesn't know that
"dst" and "src" don't overlap.  Adding __restrict__ helps
(I don't know why it didn't work before):

void f(S * __restrict__ dst, S * __restrict__ src, S * end)
{
  while (src != end) {
    new (dst++) S(std::move(*src));
    (*src).~S();
    ++src;
  }
}

..L10:
        testl   %esi, %esi
        je      .L3
        movl    (%ebx), %eax
        movl    $0, (%ebx)
        movl    %eax, (%esi)
..L4:
        addl    $4, %ebx
        addl    $4, %esi
        cmpl    %ebx, %edi
        jne     .L10

So, the destructor invocation went away entirely, including
the condition branch. It seems worthwhile to invest in syntax
means to inform the compiler of pointer value restrictions;
such a facility would presumably be more widely applicable
than destructive moves.

Jens

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/58DD223A.3050900%40gmx.net.

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Thu, 30 Mar 2017 17:28:14 +0200
Raw View
On 03/30/2017 01:05 AM, Thiago Macieira wrote:
> Here are my numbers. This was also posted to the Qt development mailing list,
> where the same discussion is happening.
>
> Source code: http://paste.opensuse.org/83426813
> [Does not compile with standard Qt, use [1]]
>
> Without further ado, results. Analysis and conclusions below.

> copyComplex,"44.778.841,93750",84%,
> moveComplex,"53.097.208,06250",100%,

> copyComplex,"68.326.384,37500",91%,
> moveComplex,"75.145.256,50000",100%,

This is odd.  Why is the copy less expensive than the move?

Jens

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/58DD240E.3030506%40gmx.net.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Thu, 30 Mar 2017 08:54:26 -0700
Raw View
On quarta-feira, 29 de mar=C3=A7o de 2017 22:23:12 PDT Andrey Davydov wrote=
:
> Ok, there is my benchmark, tell me please if it contains any systematic
> error.
[cut]
> Results for `gcc -O2`:
> relocate using move  : 18ms
> relocate using memcpy: 4ms
> Results for `gcc -O3`:
> relocate using move  : 15ms
> relocate using memcpy: 4ms

Nope, that looks like what I'd expect. You gave me a scare for a second for=
=20
using std::vector<int>, but you're not measuring vector's time for moving=
=20
ints, but the time to move std::vector<int> itself. Your code makes a=20
(correct) assumption about whether libstdc++'s std::vector<int> is=20
relocatable.

One hint: run for longer than a couple of milliseconds, to get any transien=
ts=20
smoothed out.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/14488928.NcbbRB8Rv6%40tjmaciei-mobl1.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Thu, 30 Mar 2017 09:43:55 -0700
Raw View
On quinta-feira, 30 de mar=C3=A7o de 2017 08:28:14 PDT Jens Maurer wrote:
> On 03/30/2017 01:05 AM, Thiago Macieira wrote:
> > Here are my numbers. This was also posted to the Qt development mailing
> > list, where the same discussion is happening.
> >=20
> > Source code: http://paste.opensuse.org/83426813
> > [Does not compile with standard Qt, use [1]]
> >=20
> > Without further ado, results. Analysis and conclusions below.
> >=20
> > copyComplex,"44.778.841,93750",84%,
> > moveComplex,"53.097.208,06250",100%,
> >=20
> > copyComplex,"68.326.384,37500",91%,
> > moveComplex,"75.145.256,50000",100%,
>=20
> This is odd.  Why is the copy less expensive than the move?

Checking the assembly that Clang and ICC generated...

For ICC: I can see the move constructor there. ICC decided to unroll the=20
moving loop once, so it moves two QStrings per loop, which makes each loop=
=20
operate on a multiple of 16 (64-bit QString for me is 24 bytes). In the cop=
y=20
case, I do not see any unrolling. So it's possible that the difference can =
be=20
attributed to the additional overhead due to the unrolling.

Remember: QString is copy-on-write and since the QStrings in this are all=
=20
empty, the copy constructor copies the 24 bytes, tests one bit and then=20
continues to the next iteration. It's quite fast.

For Clang: there's no difference! Somehow, Clang called the move constructo=
r=20
in the copy case! That doesn't make sense to me. Why is it doing that?

As for the difference in time, it appears to be noise. When running again, =
the=20
move and copy trade places as the fastest.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/2015472.hKbLxcezYk%40tjmaciei-mobl1.

.


Author: Andrey Davydov <andrey.a.davydov@gmail.com>
Date: Thu, 30 Mar 2017 23:00:33 -0700 (PDT)
Raw View
------=_Part_73_710558166.1490940033652
Content-Type: multipart/alternative;
 boundary="----=_Part_74_251388050.1490940033652"

------=_Part_74_251388050.1490940033652
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable


>
> On quarta-feira, 29 de mar=C3=A7o de 2017 22:23:12 PDT Andrey Davydov wro=
te:=20
> > Ok, there is my benchmark, tell me please if it contains any systematic=
=20
> > error.=20
> [cut]=20
> > Results for `gcc -O2`:=20
> > relocate using move  : 18ms=20
> > relocate using memcpy: 4ms=20
> > Results for `gcc -O3`:=20
> > relocate using move  : 15ms=20
> > relocate using memcpy: 4ms=20
>
> Nope, that looks like what I'd expect. You gave me a scare for a second=
=20
> for=20
> using std::vector<int>, but you're not measuring vector's time for moving=
=20
> ints, but the time to move std::vector<int> itself. Your code makes a=20
> (correct) assumption about whether libstdc++'s std::vector<int> is=20
> relocatable.
>
I have used std::vector (instead of std::unique_ptr, for example) because=
=20
its move constructor consists of quite a few operations (relatively to=20
unique_ptr).

>
> One hint: run for longer than a couple of milliseconds, to get any=20
> transients=20
> smoothed out.=20
>
There is updated benchmark code:=20
https://gist.github.com/AndreyG/76ed9fd1e69a48dc1aad38f0125c45a8
It can be seen that when the test dataset is placed entirely in L3 cache,=
=20
then relocation using memcpy is faster about 4 times (for instance, 213ms=
=20
against 854 ms). In the other case it's faster slightly less th 2 times=20
(2594 against 4751ms).

>
> --=20
> Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org=20
>    Software Architect - Intel Open Source Technology Center=20
>
>

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/deac69c9-6681-4c7d-be65-37d9d4d1509e%40isocpp.or=
g.

------=_Part_74_251388050.1490940033652
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;">On quarta-fei=
ra, 29 de mar=C3=A7o de 2017 22:23:12 PDT Andrey Davydov wrote:
<br>&gt; Ok, there is my benchmark, tell me please if it contains any syste=
matic
<br>&gt; error.
<br>[cut]
<br>&gt; Results for `gcc -O2`:
<br>&gt; relocate using move =C2=A0: 18ms
<br>&gt; relocate using memcpy: 4ms
<br>&gt; Results for `gcc -O3`:
<br>&gt; relocate using move =C2=A0: 15ms
<br>&gt; relocate using memcpy: 4ms
<br>
<br>Nope, that looks like what I&#39;d expect. You gave me a scare for a se=
cond for=20
<br>using std::vector&lt;int&gt;, but you&#39;re not measuring vector&#39;s=
 time for moving=20
<br>ints, but the time to move std::vector&lt;int&gt; itself. Your code mak=
es a=20
<br>(correct) assumption about whether libstdc++&#39;s std::vector&lt;int&g=
t; is=20
<br>relocatable.<br></blockquote><div>I have used std::vector (instead of s=
td::unique_ptr, for example) because its move constructor consists of quite=
 a few operations (relatively to unique_ptr).</div><blockquote class=3D"gma=
il_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid=
;padding-left: 1ex;">
<br>One hint: run for longer than a couple of milliseconds, to get any tran=
sients=20
<br>smoothed out.
<br></blockquote><div>There is updated benchmark code: https://gist.github.=
com/AndreyG/76ed9fd1e69a48dc1aad38f0125c45a8</div><div>It can be seen that =
when the test dataset is placed entirely in L3 cache, then relocation using=
 memcpy is faster about 4 times (for instance, 213ms against 854 ms). In th=
e other case it&#39;s faster slightly less th 2 times (2594 against 4751ms)=
..</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>--=20
<br>Thiago Macieira - thiago (AT) <a href=3D"http://macieira.info" target=
=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D&#39;http://www.goo=
gle.com/url?q\x3dhttp%3A%2F%2Fmacieira.info\x26sa\x3dD\x26sntz\x3d1\x26usg\=
x3dAFQjCNEswDUBNCNanbu7euhqLn_62FW8ag&#39;;return true;" onclick=3D"this.hr=
ef=3D&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fmacieira.info\x26sa\x=
3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEswDUBNCNanbu7euhqLn_62FW8ag&#39;;return t=
rue;">macieira.info</a> - thiago (AT) <a href=3D"http://kde.org" target=3D"=
_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D&#39;http://www.google.=
com/url?q\x3dhttp%3A%2F%2Fkde.org\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNH=
GRJdo5_JYG1DowztwAHAKs80XSA&#39;;return true;" onclick=3D"this.href=3D&#39;=
http://www.google.com/url?q\x3dhttp%3A%2F%2Fkde.org\x26sa\x3dD\x26sntz\x3d1=
\x26usg\x3dAFQjCNHGRJdo5_JYG1DowztwAHAKs80XSA&#39;;return true;">kde.org</a=
>
<br>=C2=A0 =C2=A0Software Architect - Intel Open Source Technology Center
<br>
<br></blockquote></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/deac69c9-6681-4c7d-be65-37d9d4d1509e%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/deac69c9-6681-4c7d-be65-37d9d4d1509e=
%40isocpp.org</a>.<br />

------=_Part_74_251388050.1490940033652--

------=_Part_73_710558166.1490940033652--

.


Author: Antony Polukhin <antoshkka@gmail.com>
Date: Fri, 31 Mar 2017 10:27:12 +0300
Raw View
2017-03-31 9:00 GMT+03:00 Andrey Davydov <andrey.a.davydov@gmail.com>:
>> On quarta-feira, 29 de mar=C3=A7o de 2017 22:23:12 PDT Andrey Davydov wr=
ote:
>> > Ok, there is my benchmark, tell me please if it contains any systemati=
c
>> > error.
>> [cut]
>> > Results for `gcc -O2`:
>> > relocate using move  : 18ms
>> > relocate using memcpy: 4ms
>> > Results for `gcc -O3`:
>> > relocate using move  : 15ms
>> > relocate using memcpy: 4ms

As I understand, the is_relocatable trait is mostly for speeding up
the std::vector::resize/uinitialized_move+deallocate_range/std::vector::res=
erve.

GCC's std::vector::reserve has the following code:

  pointer __tmp =3D _M_allocate_and_copy(__n,
    _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_start),
    _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_finish));
  std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
                _M_get_Tp_allocator());

From the banchmarks from above it seems that std::vector::reserve is
not well optimized.



Here are some of my experiments. The following chunk of code is very
well optimized by GCC 7.0.1 20170330 with -std=3Dc++1z -O2

#include <memory>
void relocate_using_move(std::shared_ptr<int>*__restrict__ new_buffer,
std::shared_ptr<int>*__restrict__ old_buffer, size_t size) {
    typedef std::shared_ptr<int> T;
    for (size_t i =3D 0; i !=3D size; ++i) {
        new (new_buffer + i) T{std::move(old_buffer[i])};
        old_buffer[i].~T();
    }
}


Disassembly looks like a simple loop:

relocate_using_move(std::shared_ptr<int>*, std::shared_ptr<int>*,
unsigned long):
        test    rdx, rdx
        je      .L1
        sal     rdx, 4
        add     rdx, rdi
..L3:
        mov     rax, QWORD PTR [rsi]
        add     rdi, 16
        add     rsi, 16
        mov     QWORD PTR [rdi-16], rax
        mov     rax, QWORD PTR [rsi-8]
        mov     QWORD PTR [rdi-8], rax
        cmp     rdi, rdx
        jne     .L3
..L1:
        rep ret


But any minor change to that code and the disassembly becomes *much*
worse. Minor changes I've tried:
* removing the first __restrict__
* removing the second __restrict__
* making 2 loops instead of a single one:

void relocate_using_move(std::shared_ptr<int>*__restrict__ new_buffer,
std::shared_ptr<int>*__restrict__ old_buffer, size_t size) {
    typedef std::shared_ptr<int> T;
    for (size_t i =3D 0; i !=3D size; ++i) {
        new (new_buffer + i) T{std::move(old_buffer[i])};
    }

    for (size_t i =3D 0; i !=3D size; ++i) {
        old_buffer[i].~T();
    }
}


GCC's std::vector::reserve has all 3 optimization barriers from above:
no __restrict__s and two loops under the hood.


QUESTION: Does the C++ memory model allows to transform

void f(T* new_buffer, T* old_buffer, size_t size) {
    for (size_t i =3D 0; i !=3D size; ++i) {
        new (new_buffer + i) T{std::move(old_buffer[i])};
    }

    for (size_t i =3D 0; i !=3D size; ++i) {
        old_buffer[i].~T();
    }
}


into

void f(T* __restrict__ new_buffer, T* __restrict__ old_buffer, size_t size)=
 {
    for (size_t i =3D 0; i !=3D size; ++i) {
        new (new_buffer + i) T{std::move(old_buffer[i])};
        old_buffer[i].~T();
    }
}


If the answer to the question is "yes", then it's better not to have
the proposed trait as tuning the optimizer will do the job. If the
answer is "no", then looks like the C++ memory model has to be
improved. If the answer is "no" and the memory model could not be
improved, then the proposed trait or some unitialized_move_destroy
function seem to be the right answer.

--=20
Best regards,
Antony Polukhin

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAKqmYPYUe7i%2BKCTnnKcdKe4yiVir6O1rtWtecbxhw9uRq=
_7-VA%40mail.gmail.com.

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Fri, 31 Mar 2017 09:41:43 +0200
Raw View
On 2017-03-31 09:27, Antony Polukhin wrote:
> Here are some of my experiments. The following chunk of code is very
> well optimized by GCC 7.0.1 20170330 with -std=c++1z -O2
>
> #include <memory>
> void relocate_using_move(std::shared_ptr<int>*__restrict__ new_buffer,
> std::shared_ptr<int>*__restrict__ old_buffer, size_t size) {
>     typedef std::shared_ptr<int> T;
>     for (size_t i = 0; i != size; ++i) {
>         new (new_buffer + i) T{std::move(old_buffer[i])};
>         old_buffer[i].~T();
>     }
> }
>
>
> Disassembly looks like a simple loop:
>
> relocate_using_move(std::shared_ptr<int>*, std::shared_ptr<int>*,
> unsigned long):
>         test    rdx, rdx
>         je      .L1
>         sal     rdx, 4
>         add     rdx, rdi
> .L3:
>         mov     rax, QWORD PTR [rsi]
>         add     rdi, 16
>         add     rsi, 16
>         mov     QWORD PTR [rdi-16], rax
>         mov     rax, QWORD PTR [rsi-8]
>         mov     QWORD PTR [rdi-8], rax
>         cmp     rdi, rdx
>         jne     .L3
> .L1:
>         rep ret

This matches my experience; see my other e-mail.
(The useless null pointer check is now removed; good.
And the dead store to the move-source has gone away, too.)

In order to get optimal performance, we now need to teach
the gcc optimizer to recognize that this is a simple
memcpy loop.  Although recent Intel hardware should get
pretty close to memcpy speeds with a simple loop like
the above.

> QUESTION: Does the C++ memory model allows to transform
>
> void f(T* new_buffer, T* old_buffer, size_t size) {
>     for (size_t i = 0; i != size; ++i) {
>         new (new_buffer + i) T{std::move(old_buffer[i])};
>     }
>
>     for (size_t i = 0; i != size; ++i) {
>         old_buffer[i].~T();
>     }
> }
>
>
> into
>
> void f(T* __restrict__ new_buffer, T* __restrict__ old_buffer, size_t size) {
>     for (size_t i = 0; i != size; ++i) {
>         new (new_buffer + i) T{std::move(old_buffer[i])};
>         old_buffer[i].~T();
>     }
> }

The standard library can certainly do that transformation inside its
std::vector implementation, provided that the move constructor is
non-throwing.

On a C++ level, we also need a non-throwing move constructor.
Other than that, I don't think std::vector specifies when it
calls move constructors vs. destructors when it reallocates,
so the transformation is probably good under as-if.

> If the answer to the question is "yes", then it's better not to have
> the proposed trait as tuning the optimizer will do the job.

Why don't we simply ask the standard library implementer to fuse
the two loops and add a few __restrict__ annotations?

>  If the
> answer is "no", then looks like the C++ memory model has to be
> improved. If the answer is "no" and the memory model could not be
> improved, then the proposed trait or some unitialized_move_destroy
> function seem to be the right answer.

Jens

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/7ef5e99c-ead2-9f20-91fa-8ec9e08f2836%40gmx.net.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Fri, 31 Mar 2017 09:06:22 -0700
Raw View
On sexta-feira, 31 de mar=C3=A7o de 2017 00:41:43 PDT Jens Maurer wrote:
> Why don't we simply ask the standard library implementer to fuse
> the two loops and add a few __restrict__ annotations?

We should, but from my benchmarks, we're still leaving 50% of the performan=
ce=20
on the floor by not permitting realloc().

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/3866927.bvqmegt90S%40tjmaciei-mobl1.

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Fri, 31 Mar 2017 19:31:27 +0200
Raw View
On 03/31/2017 06:06 PM, Thiago Macieira wrote:
> On sexta-feira, 31 de mar=C3=A7o de 2017 00:41:43 PDT Jens Maurer wrote:
>> Why don't we simply ask the standard library implementer to fuse
>> the two loops and add a few __restrict__ annotations?
>=20
> We should, but from my benchmarks, we're still leaving 50% of the perform=
ance=20
> on the floor by not permitting realloc().

But I thought the benchmark setup was such that realloc() would actually
extend the allocation in-place and not perform a copy at all?

If so, a future interface for C++ realloc() could take that into
account. Not copying or moving at all is certainly an option for
std::vector when being enlarged. if the memory subsystem allows it.
Note that this also works for types that are not relocatable.

Jens


--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/58DE926F.8010607%40gmx.net.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Fri, 31 Mar 2017 16:10:55 -0700
Raw View
On sexta-feira, 31 de mar=C3=A7o de 2017 10:31:27 PDT Jens Maurer wrote:
> On 03/31/2017 06:06 PM, Thiago Macieira wrote:
> > On sexta-feira, 31 de mar=C3=A7o de 2017 00:41:43 PDT Jens Maurer wrote=
:
> >> Why don't we simply ask the standard library implementer to fuse
> >> the two loops and add a few __restrict__ annotations?
> >=20
> > We should, but from my benchmarks, we're still leaving 50% of the
> > performance on the floor by not permitting realloc().
>=20
> But I thought the benchmark setup was such that realloc() would actually
> extend the allocation in-place and not perform a copy at all?

Yes and no.

Yes, I did design it so that it could do that. And as I said in the analysi=
s=20
and conclusions, given a good arena allocator, that's exactly what will hap=
pen=20
and therefore is a valid condition.

No because realloc() actually doesn't do it. When debugging another issue=
=20
related to qReallocAligned, I found out that glibc's realloc() will often m=
ove=20
things when the block grows. It probably has a heuristic algorithm to avoid=
=20
fragmentation. More importantly, when the size crosses a certain threshold=
=20
(128kB on glibc's malloc), it will start using mmap instead of the regular=
=20
heap, so it *has* to move, but again after that it will begin using mremap(=
)=20
which will have a ~O(1) cost instead of O(n).

In all, I find that this is actually very representative of real world=20
situations, since there were realloc() calls that did not need memcpy and=
=20
there were some that did.

> If so, a future interface for C++ realloc() could take that into
> account. Not copying or moving at all is certainly an option for
> std::vector when being enlarged. if the memory subsystem allows it.
> Note that this also works for types that are not relocatable.

Non-relocatable types can't benefit from realloc() that can memcpy or mrema=
p=20
behind your back.

We've been through this: that would require realloc_in_place() but no one h=
as=20
got WG14 to accept that.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/2695933.63tGj69oSs%40tjmaciei-mobl1.

.


Author: Matthew Fioravante <fmatthew5876@gmail.com>
Date: Mon, 17 Apr 2017 10:18:52 -0700 (PDT)
Raw View
------=_Part_148_1751171164.1492449532611
Content-Type: multipart/alternative;
 boundary="----=_Part_149_216102872.1492449532611"

------=_Part_149_216102872.1492449532611
Content-Type: text/plain; charset=UTF-8

I have not read the entire thread, but I can say one thing about this.

If one of the perceived goals of this proposal is to enable realloc()
support in vector, then I think that's extremely misguided. The problem
there is not being able to define relocatability but instead that the
interface to realloc() is fundamentally broken. Instead of adding a kludge
around realloc(), just fix realloc() instead.

A better approach is a memory allocation function like bool expand(T*,
size_t new_size), which either grows the allocation in place if it can or
returns false if it cannot. Then the calling code (which is templated on T)
can fallback to allocating a new buffer and doing the copy/move operations
as it currently does.

I think one of the reasons facebook and others introduce is_relocatable()
is because realloc() is all we have currently. If expand() existed, do you
think they would bother? I've done this is_relocatable() thing before. Its
a huge pain and if I had expand() I wouldn't have bothered.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/819f1d69-3c6b-4ece-b67e-eaf17fde97e2%40isocpp.org.

------=_Part_149_216102872.1492449532611
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I have not read the entire thread, but I can say one thing=
 about this.<div><br></div><div>If one of the perceived goals of this propo=
sal is to enable realloc() support in vector, then I think that&#39;s extre=
mely misguided. The problem there is not being able to define relocatabilit=
y but instead that the interface to realloc() is fundamentally broken. Inst=
ead of adding a kludge around realloc(), just fix realloc() instead.</div><=
div><br></div><div>A better approach is a memory allocation function like b=
ool expand(T*, size_t new_size), which either grows the allocation in place=
 if it can or returns false if it cannot. Then the calling code (which is t=
emplated on T) can fallback to allocating a new buffer and doing the copy/m=
ove operations as it currently does.</div><div><br></div><div>I think one o=
f the reasons facebook and others introduce is_relocatable() is because rea=
lloc() is all we have currently. If expand() existed, do you think they wou=
ld bother? I&#39;ve done this is_relocatable() thing before. Its a huge pai=
n and if I had expand() I wouldn&#39;t have bothered.</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/819f1d69-3c6b-4ece-b67e-eaf17fde97e2%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/819f1d69-3c6b-4ece-b67e-eaf17fde97e2=
%40isocpp.org</a>.<br />

------=_Part_149_216102872.1492449532611--

------=_Part_148_1751171164.1492449532611--

.


Author: Matthew Fioravante <fmatthew5876@gmail.com>
Date: Mon, 17 Apr 2017 10:30:14 -0700 (PDT)
Raw View
------=_Part_320_1639465599.1492450214082
Content-Type: multipart/alternative;
 boundary="----=_Part_321_1810824353.1492450214082"

------=_Part_321_1810824353.1492450214082
Content-Type: text/plain; charset=UTF-8



On Monday, April 17, 2017 at 12:18:52 PM UTC-5, Matthew Fioravante wrote:
>
> I have not read the entire thread, but I can say one thing about this.
>
> If one of the perceived goals of this proposal is to enable realloc()
> support in vector, then I think that's extremely misguided. The problem
> there is not being able to define relocatability but instead that the
> interface to realloc() is fundamentally broken. Instead of adding a kludge
> around realloc(), just fix realloc() instead.
>
> A better approach is a memory allocation function like bool expand(T*,
> size_t new_size), which either grows the allocation in place if it can or
> returns false if it cannot. Then the calling code (which is templated on T)
> can fallback to allocating a new buffer and doing the copy/move operations
> as it currently does.
>
> I think one of the reasons facebook and others introduce is_relocatable()
> is because realloc() is all we have currently. If expand() existed, do you
> think they would bother? I've done this is_relocatable() thing before. Its
> a huge pain and if I had expand() I wouldn't have bothered.
>


I'd also like to point out that in place reallocation from expand() works
for any type T. Whereas realloc() is limited to only T's that are
relocatable. That's another huge disadvantage of realloc(). Its really not
a function that can be useful in C++ and we need to stop discussing complex
hacks like is_relocatable<T> to try to use it.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/dc163363-0ad5-47bd-80b4-9f74a7653cce%40isocpp.org.

------=_Part_321_1810824353.1492450214082
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Monday, April 17, 2017 at 12:18:52 PM UTC-5, Ma=
tthew Fioravante wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0=
;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div di=
r=3D"ltr">I have not read the entire thread, but I can say one thing about =
this.<div><br></div><div>If one of the perceived goals of this proposal is =
to enable realloc() support in vector, then I think that&#39;s extremely mi=
sguided. The problem there is not being able to define relocatability but i=
nstead that the interface to realloc() is fundamentally broken. Instead of =
adding a kludge around realloc(), just fix realloc() instead.</div><div><br=
></div><div>A better approach is a memory allocation function like bool exp=
and(T*, size_t new_size), which either grows the allocation in place if it =
can or returns false if it cannot. Then the calling code (which is template=
d on T) can fallback to allocating a new buffer and doing the copy/move ope=
rations as it currently does.</div><div><br></div><div>I think one of the r=
easons facebook and others introduce is_relocatable() is because realloc() =
is all we have currently. If expand() existed, do you think they would both=
er? I&#39;ve done this is_relocatable() thing before. Its a huge pain and i=
f I had expand() I wouldn&#39;t have bothered.</div></div></blockquote><div=
><br></div><div><br></div><div>I&#39;d also like to point out that in place=
 reallocation from expand() works for any type T. Whereas realloc() is limi=
ted to only T&#39;s that are relocatable. That&#39;s another huge disadvant=
age of realloc(). Its really not a function that can be useful in C++ and w=
e need to stop discussing complex hacks like is_relocatable&lt;T&gt; to try=
 to use it.</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/dc163363-0ad5-47bd-80b4-9f74a7653cce%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/dc163363-0ad5-47bd-80b4-9f74a7653cce=
%40isocpp.org</a>.<br />

------=_Part_321_1810824353.1492450214082--

------=_Part_320_1639465599.1492450214082--

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Mon, 17 Apr 2017 10:57:12 -0700
Raw View
Em segunda-feira, 17 de abril de 2017, =C3=A0s 10:18:52 PDT, Matthew Fiorav=
ante=20
escreveu:
> If one of the perceived goals of this proposal is to enable realloc()
> support in vector, then I think that's extremely misguided. The problem
> there is not being able to define relocatability but instead that the
> interface to realloc() is fundamentally broken. Instead of adding a kludg=
e
> around realloc(), just fix realloc() instead.

I don't remember for certain if anyone even asked WG14 for this. I have a=
=20
vague memory of someone reporting that they did and WG14 wasn't interested.=
=20
That means it's practically a closed case: we can't fix realloc, period.

> A better approach is a memory allocation function like bool expand(T*,
> size_t new_size), which either grows the allocation in place if it can or
> returns false if it cannot. Then the calling code (which is templated on =
T)
> can fallback to allocating a new buffer and doing the copy/move operation=
s
> as it currently does.

Yes, we would like that. Other proposed names were realloc_inplace() or=20
malloc_resize(). That would be even better than using realloc, since we cou=
ld=20
attempt to extend the allocation for non-relocatable T.=20

But looks like it will not be.

> I think one of the reasons facebook and others introduce is_relocatable()
> is because realloc() is all we have currently. If expand() existed, do yo=
u
> think they would bother? I've done this is_relocatable() thing before. It=
s
> a huge pain and if I had expand() I wouldn't have bothered.

Yes. expand() or resize() or whatever won't obviate the need for using real=
loc=20
for relocatable T, though. It's possible some implementations of realloc ca=
n=20
be even more efficient than malloc+memcpy+free, such as for example changin=
g the=20
page tables and doing no memcpy. Therefore, realloc support is still requir=
ed.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/2008610.Xlf5RU7XW7%40tjmaciei-mobl1.

.


Author: Magnus Fromreide <magfr@lysator.liu.se>
Date: Tue, 18 Apr 2017 08:28:48 +0200
Raw View
On Mon, Apr 17, 2017 at 10:57:12AM -0700, Thiago Macieira wrote:
> Em segunda-feira, 17 de abril de 2017, =C3=A0s 10:18:52 PDT, Matthew Fior=
avante=20
> escreveu:
> > If one of the perceived goals of this proposal is to enable realloc()
> > support in vector, then I think that's extremely misguided. The problem
> > there is not being able to define relocatability but instead that the
> > interface to realloc() is fundamentally broken. Instead of adding a klu=
dge
> > around realloc(), just fix realloc() instead.
>=20
> I don't remember for certain if anyone even asked WG14 for this. I have a=
=20
> vague memory of someone reporting that they did and WG14 wasn't intereste=
d.=20
> That means it's practically a closed case: we can't fix realloc, period.

Are you talking about c/n1085? That proposal was submitted to the WG14 but
nobody presented it and offered to do the work - as far as I understand
the standardization business that means they weren't interested enough
to do the work for us but they were not outright hostile about it.

This is at least how I am interpreting Howard Hinnant's message in the
thread with subject "try_realloc" from 2015-08-02.

/MF

(Does anyone know how to provide a stable link to a message?)

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/20170418062848.GD608%40noemi.

.