Topic: Complexities caused by using unique_ptr and move semantics


Author: Matthew Fioravante <fmatthew5876@gmail.com>
Date: Thu, 23 Mar 2017 09:38:19 -0700 (PDT)
Raw View
------=_Part_184_1227975421.1490287099071
Content-Type: multipart/alternative;
 boundary="----=_Part_185_1235225468.1490287099072"

------=_Part_185_1235225468.1490287099072
Content-Type: text/plain; charset=UTF-8

I don't have a proposal or a real solution. This is more intended to
highlight some of the problems related to unique ownership and move
semantics.

1. Its too easy to accidentally use a moved from object by mistake

Consider this code:

void Container::addThing(unique_ptr<Thing> p) {
  this->_things.push_back(std::move(p));
  if(logging_enabled) {
   std::cout << "Added thing " << p->name() << " " << p->foo() << " " << p->
bar() << std::endl;
  }
  return;
}

I've seen this kind of bug many times. Its very easy to write and the
compiler provides no help to you. Even better since the bug is hidden when
logging is disabled, it could easily pass into production. Its also
somewhat of an expert problem when explaining to novices.

Now here's an attempt to fix the bug the right way. But we still have a
mistake! Again no help from the compiler. Also unless you're really paying
attention, a quick skim through the code will likely miss this one.

void Container::addThing(unique_ptr<Thing> p) {
  auto* pc = p.get();
  this->_things.push_back(std::move(p));
  if(logging_enabled) {
   std::cout << "Added thing " << pc->name() << " " << pc->foo() << " " << p
->bar() << std::endl;
  }
  return;
}

After we move p into _things, we never need to touch p again. Unfortunately
in this case and many others, we can't really introduce scopes with {} to
eliminate p from the local namespace and prevent these kinds of bugs.

A possible solution here might be some kind of [[discard]] attribute or a
std::move_final() which is std::move() + [[discard]] together. So that the
compiler would warn on any use of p after the move.


2. unique_ptr<T> and T* being different types can cause pessimizations
because of language rules.

Of course its a good thing that these types are different. One is an owner
and one is not. Using a different type means we can enlist the help of the
compiler to enforce correctness.

Sometimes I have a container with keeps a set of unique_ptrs, and I want to
view that set.

class OwningContainer {
 public:
  array_view<const unique_ptr<Thing>> getThings() const { return _things; }
 private:
  std::vector<unique_ptr<Thing>> _things;
};

class NonOwningContainer {
 public:
  array_view<const Thing*> getThings() const { return _things; }
 private:
  std::vector<Thing*> _things;
};

//Out of line function, maybe lives in a 3rd party library.
void f(array_view<const Thing*> things);

void g(const OwningContainer& c){
  f(c.getThings()); //Compiler Error
}
void h(const NonOwningContainer& c) {
  f(c.getThings()); //Ok
}

The getThings() method of OwningContainer and NonOwningContainer methods
have the exact same semantics. We're getting a const view of the stored
thing pointers. The returned objects are even bitwise and machine code
(after optimization) identical, but are "marked up" by the compiler with
different types.

From the limited perspective of the code calling getThings(), whether or
not the container owns the pointers is an implementation detail. The caller
does not and should not care whether the pointers are stored raw,
unique_ptr. He just wants to view the collection and do something with it.

The big problem here is that the return types of getThings() are different.
This means that in a generic context, you need to start introducing
templates in order to handle all possible pointer types. Adding templates
complicates the code and slows down compile times.

Also since const unique_ptr<T> and const T* are semantically and even
bitwise identical, using templates here will unnecessarily bloat your code
with 2 functions that do the exact same thing. This increases your binary
size and puts more pressure on the icache.

In this example, we must change f() to be a template. Even though the
actual compiled down machine code will be identical. The biggest problem I
have with this example is that the problem comes from artificial language
rules and not physical limits about how hardware and memory works. That
goes against the zero overhead principle of C++.

In order to avoid making f() a template here, there are a few options today
we can try with OwningContainer:
1. Return vector<Thing*> by value, doing a copy and memory allocations at
every call. (very slow)
2. Store a second vector<Thing*> inside OwningContainer, keep it in sync
with the unique_ptr version, and return it in getThings(). (twice memory
usage, slow, complicated, error prone)
3. Abandon unique_ptr inside of OwningContainer, and go back to manually
managing the memory. (error prone and greatly increases development time)

Possible solutions to this include:
1. Add some kind of way to alias a unique_ptr<T> into a T*. Letting me
essentially convert an array_view<const unique_ptr<T>> to array_view<const
T>. In terms of how the implementation actually works on the machine, this
is a trivial no-op. In terms of language rules its a complete nightmare.
2. Provide a specialized unique_vector<T*> which essentially operates like
vector<unique_ptr<T>>, but exposes T* in its const interface. Then we can
construct array_view<const T> over vector<T> and unique_vector<T>. Hiding
the ownership implementation details and avoiding the need to for
artificial templates.  This would solve the immediate example I've shown,
but I'm not sure if its too specific and leaves out other similar
situations.

How would you solve these 2 issues?

Have you seen any other complexities show up in your code from adopting
unique_ptr?

--
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/46a85060-631b-49e5-94f3-ab07429d8085%40isocpp.org.

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

<div dir=3D"ltr">I don&#39;t have a proposal or a real solution. This is mo=
re intended to highlight some of the problems related to unique ownership a=
nd move semantics.<div><br></div><div>1. Its too easy to accidentally use a=
 moved from object by mistake</div><div><br></div><div>Consider this code:<=
/div><div><br></div><div><div class=3D"prettyprint" style=3D"background-col=
or: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: sol=
id; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint">=
<div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-=
by-prettify">void</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Co=
ntainer</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">addThing</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify">unique_ptr</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">Thing</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> p</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #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: #008;" class=3D"styled-by-prettify=
">this</span><span style=3D"color: #660;" class=3D"styled-by-prettify">-&gt=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">_things</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">push_back</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 style=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: #000;" class=3D"style=
d-by-prettify">p</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">));</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br>=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">=
if</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">logging_enabled</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0std</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">cout </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=
=3D"styled-by-prettify">&quot;Added thing &quot;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> p</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">-&gt;</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify">name</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">()</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #080;" class=3D"styled-by-prettify">&quot; &quot;</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> p</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">-&gt;</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">foo</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">&=
quot; &quot;</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> p</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">-&gt;</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify">bar</span><span style=
=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: #660;"=
 class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">endl</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=
">}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">return=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">}</span><font color=3D"#6=
66600"></font></div></code></div><br>I&#39;ve seen this kind of bug many ti=
mes. Its very easy to write and the compiler provides no help to you. Even =
better since the bug is hidden when logging is disabled, it could easily pa=
ss into production. Its also somewhat of an expert problem when explaining =
to novices.</div><div><br></div><div>Now here&#39;s an attempt to fix the b=
ug the right way. But we still have a mistake! Again no help from the compi=
ler. Also unless you&#39;re really paying attention, a quick skim through t=
he code will likely miss this one.</div><div><br></div><div><div class=3D"p=
rettyprint" style=3D"background-color: rgb(250, 250, 250); border-color: rg=
b(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: break-=
word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">void</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #60=
6;" class=3D"styled-by-prettify">Container</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">addThing</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">unique_ptr</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">&lt;</span><span style=3D"color: #606;" class=3D"styled-by-p=
rettify">Thing</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> p=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> pc </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> p</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">.</span><span style=3D"color: #008;" class=3D"styled-by-prettify">get</s=
pan><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 </span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">this</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">-&gt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">_things</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">push_back</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">move</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">p</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">));</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">if</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">logging_enabled</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br>=C2=A0 =C2=A0std</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">cout </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify=
">&quot;Added thing &quot;</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> pc</span><span style=3D"color: #660;" class=3D"styled-by-prettify">-&=
gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">name</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">()</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #080;" class=3D"styled-by-prettify">&quot; &quot;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> pc</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">-&gt;</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">foo</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">()</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&=
lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #080;" class=3D"styled-by-prettify">&quot; &quot;</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> p</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">-&gt;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">bar</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">e=
ndl</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 </spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">return</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></span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">}</span></div></code></div><span class=3D"=
styled-by-prettify" style=3D"font-family: monospace; background-color: rgb(=
250, 250, 250); color: rgb(102, 102, 0);"><div><br></div><div><span style=
=3D"color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; back=
ground-color: rgb(255, 255, 255);">After we move p into _things, we never n=
eed to touch p again. Unfortunately in this case and many others, we can&#3=
9;t really introduce scopes with {} to eliminate p from the local namespace=
 and prevent these kinds of bugs.=C2=A0</span></div><div><span style=3D"col=
or: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; background-=
color: rgb(255, 255, 255);"><br></span></div><div><span style=3D"color: rgb=
(34, 34, 34); font-family: Arial, Helvetica, sans-serif; background-color: =
rgb(255, 255, 255);">A possible solution here might be some kind of [[disca=
rd]] attribute or a std::move_final() which is std::move() + [[discard]] to=
gether. So that the compiler would warn on any use of p after the move.=C2=
=A0</span><br></div><div><span class=3D"styled-by-prettify" style=3D"font-f=
amily: monospace; background-color: rgb(250, 250, 250); color: rgb(102, 102=
, 0);"><br></span></div><br></span>2. unique_ptr&lt;T&gt; and T* being diff=
erent types can cause pessimizations because of language rules.</div><div><=
br></div><div>Of course its a good thing that these types are different. On=
e is an owner and one is not. Using a different type means we can enlist th=
e help of the compiler to enforce correctness.</div><div><br></div><div>Som=
etimes I have a container with keeps a set of unique_ptrs, and I want to vi=
ew that set.</div><div><br></div><div><div class=3D"prettyprint" style=3D"b=
ackground-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bord=
er-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"=
prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">class</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-b=
y-prettify">OwningContainer</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br>=C2=A0</span><span style=3D"color: #008;" class=3D"styled-by-prettify">p=
ublic</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 </s=
pan><font color=3D"#000088"><span style=3D"color: #000;" class=3D"styled-by=
-prettify">array_view</span></font><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">const</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> unique_ptr</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">&lt;</span><span style=3D"color: #606;" class=3D"styled-by-prettify=
">Thing</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt=
;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> getT=
hings</span><span style=3D"color: #660;" class=3D"styled-by-prettify">()</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
 style=3D"color: #008;" class=3D"styled-by-prettify">const</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"> </span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">return</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> _things</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0</=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">private</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 std</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">vector</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify">unique_ptr</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #606;=
" class=3D"styled-by-prettify">Thing</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> _things</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">c=
lass</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #606;" class=3D"styled-by-prettify">NonOwningContai=
ner</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0</span><span st=
yle=3D"color: #008;" class=3D"styled-by-prettify">public</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><font color=3D"#000=
088"><span style=3D"color: #000;" class=3D"styled-by-prettify">array_view</=
span></font><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;<=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">const</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #606;" class=3D"styled-by-prettify">Thing</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">*&gt;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> getThings</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">()</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">const</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=
"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">return<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> _things</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"><br>=C2=A0</span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">private</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 std</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">vector</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">&lt;</span><span style=3D"color: #606;" class=3D"styled-by-=
prettify">Thing</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">*&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 _things</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 st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span><span styl=
e=3D"color: #800;" class=3D"styled-by-prettify">//Out of line function, may=
be lives in a 3rd party library.</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">void</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> f</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">array=
_view</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;<=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">const</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #606;" class=3D"styled-by-prettify">Thing</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">*&gt;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> things</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">void</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> g</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">const</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">OwningC=
ontainer</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&a=
mp;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> c</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">){</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 f</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(</span><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">getThings</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">());</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D"style=
d-by-prettify">//Compiler Error</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">}</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">=
void</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> h</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">const</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #606;" class=3D"styled-by-prettify">NonOwningContainer</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> c</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: #660;" class=3D"styl=
ed-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br>=C2=A0 f</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><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">getThings</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">());</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #800;" class=3D"styled-by-prettify">//Ok</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>The getThings()=
 method of OwningContainer and NonOwningContainer methods have the exact sa=
me semantics. We&#39;re getting a const view of the stored thing pointers. =
The returned objects are even bitwise and machine code (after optimization)=
 identical, but are &quot;marked up&quot; by the compiler with different ty=
pes.</div><div><br></div><div>From the limited perspective of the code call=
ing getThings(), whether or not the container owns the pointers is an imple=
mentation detail. The caller does not and should not care whether the point=
ers are stored raw, unique_ptr. He just wants to view the collection and do=
 something with it.</div><div><br></div><div>The big problem here is that t=
he return types of getThings() are different. This means that in a generic =
context, you need to start introducing templates in order to handle all pos=
sible pointer types. Adding templates complicates the code and slows down c=
ompile times.</div><div><br></div><div>Also since const unique_ptr&lt;T&gt;=
 and const T* are semantically and even bitwise identical, using templates =
here will unnecessarily bloat your code with 2 functions that do the exact =
same thing. This increases your binary size and puts more pressure on the i=
cache.</div><div><br></div><div>In this example, we must change f() to be a=
 template. Even though the actual compiled down machine code will be identi=
cal. The biggest problem I have with this example is that the problem comes=
 from artificial language rules and not physical limits about how hardware =
and memory works. That goes against the zero overhead principle of C++.</di=
v><div><br></div><div>In order to avoid making f() a template here, there a=
re a few options today we can try with OwningContainer:</div><div>1. Return=
 vector&lt;Thing*&gt; by value, doing a copy and memory allocations at ever=
y call. (very slow)</div><div>2. Store a second vector&lt;Thing*&gt; inside=
 OwningContainer, keep it in sync with the unique_ptr version, and return i=
t in getThings(). (twice memory usage, slow, complicated, error prone)</div=
><div>3. Abandon unique_ptr inside of OwningContainer, and go back to manua=
lly managing the memory. (error prone and greatly increases development tim=
e)</div><div><br></div><div>Possible solutions to this include:</div><div>1=
.. Add some kind of way to alias a unique_ptr&lt;T&gt; into a T*. Letting me=
 essentially convert an array_view&lt;const unique_ptr&lt;T&gt;&gt; to arra=
y_view&lt;const T&gt;. In terms of how the implementation actually works on=
 the machine, this is a trivial no-op. In terms of language rules its a com=
plete nightmare.</div><div>2. Provide a specialized unique_vector&lt;T*&gt;=
 which essentially operates like vector&lt;unique_ptr&lt;T&gt;&gt;, but exp=
oses T* in its const interface. Then we can construct array_view&lt;const T=
&gt; over vector&lt;T&gt; and unique_vector&lt;T&gt;. Hiding the ownership =
implementation details and avoiding the need to for artificial templates. =
=C2=A0This would solve the immediate example I&#39;ve shown, but I&#39;m no=
t sure if its too specific and leaves out other similar situations.</div><d=
iv><br></div><div>How would you solve these 2 issues?</div><div><br></div><=
div>Have you seen any other complexities show up in your code from adopting=
 unique_ptr?</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/46a85060-631b-49e5-94f3-ab07429d8085%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/46a85060-631b-49e5-94f3-ab07429d8085=
%40isocpp.org</a>.<br />

------=_Part_185_1235225468.1490287099072--

------=_Part_184_1227975421.1490287099071--

.


Author: Sean Middleditch <sean.middleditch@gmail.com>
Date: Fri, 24 Mar 2017 14:57:11 -0700 (PDT)
Raw View
------=_Part_856_1014739906.1490392631298
Content-Type: multipart/alternative;
 boundary="----=_Part_857_1938372957.1490392631299"

------=_Part_857_1938372957.1490392631299
Content-Type: text/plain; charset=UTF-8

On Thursday, March 23, 2017 at 9:38:19 AM UTC-7, Matthew Fioravante wrote:
>
> 1. Its too easy to accidentally use a moved from object by mistake
>

This is a problem with C++'s move semantics (e.g., non-destructive move and
unspecific states). These problems have been discussed plenty of times
before, particularly in destructive-move threads.

One solution in the works may be contract programming. Some of the
proposals allow a function to set a post-condition state on an object which
can be verified by a compiler or static analysis in a pre-condition. e.g.,
unique_ptr might have something like:

  [[post_condition(src): empty]
  unique_ptr(unique_ptr&& src);

  [[pre_condition(this): !empty]
  unique_ptr::operator->();

Such a setup can further hypothetically address other issues like
accidental dereferencing of default-constructed unique_ptrs. As well as a
wide host of other issues.


> 2. unique_ptr<T> and T* being different types can cause pessimizations
> because of language rules.
>

I personally most see this as a problem caused by a lack of generators, or
more specifically at the lack of range concepts (which of course are in the
works).

You usually don't want to require specifically a vector nor specifically a
pointer of any kind. You want to return an object that can be enumerated to
produce references to T objects. The vector itself or unique_ptr vs raw
pointers is an implementation detail that callers should not have to care
about.

With range concepts, this all still has to be a template of course, but you
don't have to over-worry about the specifics while using the interface.

With generators, this can be abstracted without templates (though perhaps
at a runtime cost).

Basically, you want to write something like:

  iterable<T&> foo::get_things() { return make_iterable(_things, [](auto&
p){ return *p; }); }

so user code looks unanimously like so:

  for (auto& val : f.get_things())
   do_stuff_with(val);

that specific case can be implemented as a set of "mapping_iterator" (an
iterator that returns the result of a wrapped iterator filtered through a
function) stored in a range, but there'd likely need to be something more
general to cover more use cases.

I don't know for sure if such functionality is in the ranges ts anywhere,
but I'd honestly be surprised if it wasn't.


>
> Of course its a good thing that these types are different. One is an owner
> and one is not. Using a different type means we can enlist the help of the
> compiler to enforce correctness.
>
> Sometimes I have a container with keeps a set of unique_ptrs, and I want
> to view that set.
>
> class OwningContainer {
>  public:
>   array_view<const unique_ptr<Thing>> getThings() const { return _things;
> }
>  private:
>   std::vector<unique_ptr<Thing>> _things;
> };
>
> class NonOwningContainer {
>  public:
>   array_view<const Thing*> getThings() const { return _things; }
>  private:
>   std::vector<Thing*> _things;
> };
>
> //Out of line function, maybe lives in a 3rd party library.
> void f(array_view<const Thing*> things);
>
> void g(const OwningContainer& c){
>   f(c.getThings()); //Compiler Error
> }
> void h(const NonOwningContainer& c) {
>   f(c.getThings()); //Ok
> }
>
> The getThings() method of OwningContainer and NonOwningContainer methods
> have the exact same semantics. We're getting a const view of the stored
> thing pointers. The returned objects are even bitwise and machine code
> (after optimization) identical, but are "marked up" by the compiler with
> different types.
>
> From the limited perspective of the code calling getThings(), whether or
> not the container owns the pointers is an implementation detail. The caller
> does not and should not care whether the pointers are stored raw,
> unique_ptr. He just wants to view the collection and do something with it.
>
> The big problem here is that the return types of getThings() are
> different. This means that in a generic context, you need to start
> introducing templates in order to handle all possible pointer types. Adding
> templates complicates the code and slows down compile times.
>
> Also since const unique_ptr<T> and const T* are semantically and even
> bitwise identical, using templates here will unnecessarily bloat your code
> with 2 functions that do the exact same thing. This increases your binary
> size and puts more pressure on the icache.
>
> In this example, we must change f() to be a template. Even though the
> actual compiled down machine code will be identical. The biggest problem I
> have with this example is that the problem comes from artificial language
> rules and not physical limits about how hardware and memory works. That
> goes against the zero overhead principle of C++.
>
> In order to avoid making f() a template here, there are a few options
> today we can try with OwningContainer:
> 1. Return vector<Thing*> by value, doing a copy and memory allocations at
> every call. (very slow)
> 2. Store a second vector<Thing*> inside OwningContainer, keep it in sync
> with the unique_ptr version, and return it in getThings(). (twice memory
> usage, slow, complicated, error prone)
> 3. Abandon unique_ptr inside of OwningContainer, and go back to manually
> managing the memory. (error prone and greatly increases development time)
>
> Possible solutions to this include:
> 1. Add some kind of way to alias a unique_ptr<T> into a T*. Letting me
> essentially convert an array_view<const unique_ptr<T>> to array_view<const
> T>. In terms of how the implementation actually works on the machine, this
> is a trivial no-op. In terms of language rules its a complete nightmare.
> 2. Provide a specialized unique_vector<T*> which essentially operates like
> vector<unique_ptr<T>>, but exposes T* in its const interface. Then we can
> construct array_view<const T> over vector<T> and unique_vector<T>. Hiding
> the ownership implementation details and avoiding the need to for
> artificial templates.  This would solve the immediate example I've shown,
> but I'm not sure if its too specific and leaves out other similar
> situations.
>
> How would you solve these 2 issues?
>
> Have you seen any other complexities show up in your code from adopting
> unique_ptr?
>

--
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/86aeb556-e0d7-4d68-b553-1b4163461473%40isocpp.org.

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

<div dir=3D"ltr">On Thursday, March 23, 2017 at 9:38:19 AM UTC-7, Matthew F=
ioravante 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"lt=
r">1. Its too easy to accidentally use a moved from object by mistake<br></=
div></blockquote><div><br></div><div>This is a problem with C++&#39;s move =
semantics (e.g., non-destructive move and unspecific states). These problem=
s have been discussed plenty of times before, particularly in destructive-m=
ove threads.</div><div><br></div><div>One solution in the works may be cont=
ract programming. Some of the proposals allow a function to set a post-cond=
ition state on an object which can be verified by a compiler or static anal=
ysis in a pre-condition. e.g., unique_ptr might have something like:</div><=
div><br></div><div>=C2=A0 [[post_condition(src): empty]</div><div>=C2=A0 un=
ique_ptr(unique_ptr&amp;&amp; src);</div><div><br></div><div>=C2=A0 [[pre_c=
ondition(this): !empty]</div><div>=C2=A0 unique_ptr::operator-&gt;();</div>=
<div><br></div><div>Such a setup can further hypothetically address other i=
ssues like accidental dereferencing of default-constructed unique_ptrs. As =
well as a wide host of other issues.</div><div>=C2=A0</div><blockquote clas=
s=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #c=
cc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>2. unique_ptr&lt;T&gt; a=
nd T* being different types can cause pessimizations because of language ru=
les.</div></div></blockquote><div><br></div><div>I personally most see this=
 as a problem caused by a lack of generators, or more specifically at the l=
ack of range concepts (which of course are in the works).</div><div><br></d=
iv><div>You usually don&#39;t want to require specifically a vector nor spe=
cifically a pointer of any kind. You want to return an object that can be e=
numerated to produce references to T objects. The vector itself or unique_p=
tr vs raw pointers is an implementation detail that callers should not have=
 to care about.</div><div><br></div><div>With range concepts, this all stil=
l has to be a template of course, but you don&#39;t have to over-worry abou=
t the specifics while using the interface.</div><div><br></div><div>With ge=
nerators, this can be abstracted without templates (though perhaps at a run=
time cost).</div><div><br></div><div>Basically, you want to write something=
 like:</div><div><br></div><div>=C2=A0 iterable&lt;T&amp;&gt; foo::get_thin=
gs() { return make_iterable(_things, [](auto&amp; p){ return *p; }); }<br><=
/div><div><br></div><div>so user code looks unanimously like so:</div><div>=
<br></div><div>=C2=A0 for (auto&amp; val : f.get_things())</div><div>=C2=A0=
 =C2=A0do_stuff_with(val);</div><div><br></div><div>that specific case can =
be implemented as a set of &quot;mapping_iterator&quot; (an iterator that r=
eturns the result of a wrapped iterator filtered through a function) stored=
 in a range, but there&#39;d likely need to be something more general to co=
ver more use cases.</div><div><br></div><div>I don&#39;t know for sure if s=
uch functionality is in the ranges ts anywhere, but I&#39;d honestly be sur=
prised if it wasn&#39;t.</div><div>=C2=A0</div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><div dir=3D"ltr"><div><br></div><div>Of course its a good =
thing that these types are different. One is an owner and one is not. Using=
 a different type means we can enlist the help of the compiler to enforce c=
orrectness.</div><div><br></div><div>Sometimes I have a container with keep=
s a set of unique_ptrs, and I want to view that set.</div><div><br></div><d=
iv><div 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><div>=
<span style=3D"color:#008">class</span><span style=3D"color:#000"> </span><=
span style=3D"color:#606">OwningContainer</span><span style=3D"color:#000">=
 </span><span style=3D"color:#660">{</span><span style=3D"color:#000"><br>=
=C2=A0</span><span style=3D"color:#008">public</span><span style=3D"color:#=
660">:</span><span style=3D"color:#000"><br>=C2=A0 </span><font color=3D"#0=
00088"><span style=3D"color:#000">array_view</span></font><span style=3D"co=
lor:#660">&lt;</span><span style=3D"color:#008">const</span><span style=3D"=
color:#000"> unique_ptr</span><span style=3D"color:#660">&lt;</span><span s=
tyle=3D"color:#606">Thing</span><span style=3D"color:#660">&gt;&gt;</span><=
span style=3D"color:#000"> getThings</span><span style=3D"color:#660">()</s=
pan><span style=3D"color:#000"> </span><span style=3D"color:#008">const</sp=
an><span style=3D"color:#000"> </span><span style=3D"color:#660">{</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#008">return</span><s=
pan style=3D"color:#000"> _things</span><span style=3D"color:#660">;</span>=
<span style=3D"color:#000"> </span><span style=3D"color:#660">}</span><span=
 style=3D"color:#000"><br>=C2=A0</span><span style=3D"color:#008">private</=
span><span style=3D"color:#660">:</span><span style=3D"color:#000"><br>=C2=
=A0 std</span><span style=3D"color:#660">::</span><span style=3D"color:#000=
">vector</span><span style=3D"color:#660">&lt;</span><span style=3D"color:#=
000">unique_ptr</span><span style=3D"color:#660">&lt;</span><span style=3D"=
color:#606">Thing</span><span style=3D"color:#660">&gt;&gt;</span><span sty=
le=3D"color:#000"> _things</span><span style=3D"color:#660">;</span><span s=
tyle=3D"color:#000"><br></span><span style=3D"color:#660">};</span><span st=
yle=3D"color:#000"><br><br></span><span style=3D"color:#008">class</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#606">NonOwningContai=
ner</span><span style=3D"color:#000"> </span><span style=3D"color:#660">{</=
span><span style=3D"color:#000"><br>=C2=A0</span><span style=3D"color:#008"=
>public</span><span style=3D"color:#660">:</span><span style=3D"color:#000"=
><br>=C2=A0 </span><font color=3D"#000088"><span style=3D"color:#000">array=
_view</span></font><span style=3D"color:#660">&lt;</span><span style=3D"col=
or:#008">const</span><span style=3D"color:#000"> </span><span style=3D"colo=
r:#606">Thing</span><span style=3D"color:#660">*&gt;</span><span style=3D"c=
olor:#000"> getThings</span><span style=3D"color:#660">()</span><span style=
=3D"color:#000"> </span><span style=3D"color:#008">const</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">{</span><span style=3D"c=
olor:#000"> </span><span style=3D"color:#008">return</span><span style=3D"c=
olor:#000"> _things</span><span style=3D"color:#660">;</span><span style=3D=
"color:#000"> </span><span style=3D"color:#660">}</span><span style=3D"colo=
r:#000"><br>=C2=A0</span><span style=3D"color:#008">private</span><span sty=
le=3D"color:#660">:</span><span style=3D"color:#000"><br>=C2=A0 std</span><=
span style=3D"color:#660">::</span><span style=3D"color:#000">vector</span>=
<span style=3D"color:#660">&lt;</span><span style=3D"color:#606">Thing</spa=
n><span style=3D"color:#660">*&gt;</span><span style=3D"color:#000"> _thing=
s</span><span style=3D"color:#660">;</span><span style=3D"color:#000"><br><=
/span><span style=3D"color:#660">};</span><span style=3D"color:#000"><br><b=
r></span><span style=3D"color:#800">//Out of line function, maybe lives in =
a 3rd party library.</span><span style=3D"color:#000"><br></span><span styl=
e=3D"color:#008">void</span><span style=3D"color:#000"> f</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">array_view</span><span s=
tyle=3D"color:#660">&lt;</span><span style=3D"color:#008">const</span><span=
 style=3D"color:#000"> </span><span style=3D"color:#606">Thing</span><span =
style=3D"color:#660">*&gt;</span><span style=3D"color:#000"> things</span><=
span style=3D"color:#660">);</span><span style=3D"color:#000"><br><br></spa=
n><span style=3D"color:#008">void</span><span style=3D"color:#000"> g</span=
><span style=3D"color:#660">(</span><span style=3D"color:#008">const</span>=
<span style=3D"color:#000"> </span><span style=3D"color:#606">OwningContain=
er</span><span style=3D"color:#660">&amp;</span><span style=3D"color:#000">=
 c</span><span style=3D"color:#660">){</span><span style=3D"color:#000"><br=
>=C2=A0 f</span><span style=3D"color:#660">(</span><span style=3D"color:#00=
0">c</span><span style=3D"color:#660">.</span><span style=3D"color:#000">ge=
tThings</span><span style=3D"color:#660">());</span><span style=3D"color:#0=
00"> </span><span style=3D"color:#800">//Compiler Error</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#660">}</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#008">void</span><span styl=
e=3D"color:#000"> h</span><span style=3D"color:#660">(</span><span style=3D=
"color:#008">const</span><span style=3D"color:#000"> </span><span style=3D"=
color:#606">NonOwningContainer</span><span style=3D"color:#660">&amp;</span=
><span style=3D"color:#000"> c</span><span style=3D"color:#660">)</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#660">{</span><span st=
yle=3D"color:#000"><br>=C2=A0 f</span><span style=3D"color:#660">(</span><s=
pan style=3D"color:#000">c</span><span style=3D"color:#660">.</span><span s=
tyle=3D"color:#000">getThings</span><span style=3D"color:#660">());</span><=
span style=3D"color:#000"> </span><span style=3D"color:#800">//Ok</span><sp=
an style=3D"color:#000"><br></span><span style=3D"color:#660">}</span></div=
></code></div><br>The getThings() method of OwningContainer and NonOwningCo=
ntainer methods have the exact same semantics. We&#39;re getting a const vi=
ew of the stored thing pointers. The returned objects are even bitwise and =
machine code (after optimization) identical, but are &quot;marked up&quot; =
by the compiler with different types.</div><div><br></div><div>From the lim=
ited perspective of the code calling getThings(), whether or not the contai=
ner owns the pointers is an implementation detail. The caller does not and =
should not care whether the pointers are stored raw, unique_ptr. He just wa=
nts to view the collection and do something with it.</div><div><br></div><d=
iv>The big problem here is that the return types of getThings() are differe=
nt. This means that in a generic context, you need to start introducing tem=
plates in order to handle all possible pointer types. Adding templates comp=
licates the code and slows down compile times.</div><div><br></div><div>Als=
o since const unique_ptr&lt;T&gt; and const T* are semantically and even bi=
twise identical, using templates here will unnecessarily bloat your code wi=
th 2 functions that do the exact same thing. This increases your binary siz=
e and puts more pressure on the icache.</div><div><br></div><div>In this ex=
ample, we must change f() to be a template. Even though the actual compiled=
 down machine code will be identical. The biggest problem I have with this =
example is that the problem comes from artificial language rules and not ph=
ysical limits about how hardware and memory works. That goes against the ze=
ro overhead principle of C++.</div><div><br></div><div>In order to avoid ma=
king f() a template here, there are a few options today we can try with Own=
ingContainer:</div><div>1. Return vector&lt;Thing*&gt; by value, doing a co=
py and memory allocations at every call. (very slow)</div><div>2. Store a s=
econd vector&lt;Thing*&gt; inside OwningContainer, keep it in sync with the=
 unique_ptr version, and return it in getThings(). (twice memory usage, slo=
w, complicated, error prone)</div><div>3. Abandon unique_ptr inside of Owni=
ngContainer, and go back to manually managing the memory. (error prone and =
greatly increases development time)</div><div><br></div><div>Possible solut=
ions to this include:</div><div>1. Add some kind of way to alias a unique_p=
tr&lt;T&gt; into a T*. Letting me essentially convert an array_view&lt;cons=
t unique_ptr&lt;T&gt;&gt; to array_view&lt;const T&gt;. In terms of how the=
 implementation actually works on the machine, this is a trivial no-op. In =
terms of language rules its a complete nightmare.</div><div>2. Provide a sp=
ecialized unique_vector&lt;T*&gt; which essentially operates like vector&lt=
;unique_ptr&lt;T&gt;&gt;, but exposes T* in its const interface. Then we ca=
n construct array_view&lt;const T&gt; over vector&lt;T&gt; and unique_vecto=
r&lt;T&gt;. Hiding the ownership implementation details and avoiding the ne=
ed to for artificial templates. =C2=A0This would solve the immediate exampl=
e I&#39;ve shown, but I&#39;m not sure if its too specific and leaves out o=
ther similar situations.</div><div><br></div><div>How would you solve these=
 2 issues?</div><div><br></div><div>Have you seen any other complexities sh=
ow up in your code from adopting unique_ptr?</div></div></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/86aeb556-e0d7-4d68-b553-1b4163461473%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/86aeb556-e0d7-4d68-b553-1b4163461473=
%40isocpp.org</a>.<br />

------=_Part_857_1938372957.1490392631299--

------=_Part_856_1014739906.1490392631298--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 24 Mar 2017 15:25:51 -0700 (PDT)
Raw View
------=_Part_2292_1276201536.1490394351178
Content-Type: multipart/alternative;
 boundary="----=_Part_2293_1425852513.1490394351178"

------=_Part_2293_1425852513.1490394351178
Content-Type: text/plain; charset=UTF-8

On Friday, March 24, 2017 at 5:57:11 PM UTC-4, Sean Middleditch wrote:
>
> On Thursday, March 23, 2017 at 9:38:19 AM UTC-7, Matthew Fioravante wrote:
>>
>> 1. Its too easy to accidentally use a moved from object by mistake
>>
>
> This is a problem with C++'s move semantics (e.g., non-destructive move
> and unspecific states). These problems have been discussed plenty of times
> before, particularly in destructive-move threads.
>
> One solution in the works may be contract programming. Some of the
> proposals allow a function to set a post-condition state on an object which
> can be verified by a compiler or static analysis in a pre-condition. e.g.,
> unique_ptr might have something like:
>
>   [[post_condition(src): empty]
>   unique_ptr(unique_ptr&& src);
>
>   [[pre_condition(this): !empty]
>   unique_ptr::operator->();
>
> Such a setup can further hypothetically address other issues like
> accidental dereferencing of default-constructed unique_ptrs. As well as a
> wide host of other issues.
>
>
>> 2. unique_ptr<T> and T* being different types can cause pessimizations
>> because of language rules.
>>
>
> I personally most see this as a problem caused by a lack of generators, or
> more specifically at the lack of range concepts (which of course are in the
> works).
>
> You usually don't want to require specifically a vector nor specifically a
> pointer of any kind. You want to return an object that can be enumerated to
> produce references to T objects. The vector itself or unique_ptr vs raw
> pointers is an implementation detail that callers should not have to care
> about.
>
> With range concepts, this all still has to be a template of course, but
> you don't have to over-worry about the specifics while using the interface.
>
> With generators, this can be abstracted without templates (though perhaps
> at a runtime cost).
>
> Basically, you want to write something like:
>
>   iterable<T&> foo::get_things() { return make_iterable(_things, [](auto&
> p){ return *p; }); }
>
>
That's a really bad tradeoff: type-erasing performance plus the cost of
filtering, all just to gain some increased genericity.

But Boost.Range already has something like this: `any_range
<http://www.boost.org/doc/libs/1_63_0/libs/range/doc/html/range/reference/ranges/any_range.html>`,
coupled with transforming the input range by a function
<http://www.boost.org/doc/libs/1_63_0/libs/range/doc/html/range/reference/adaptors/reference/transformed.html>
..

--
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/136fc743-bc63-48c8-b1d5-dc4084dd13cf%40isocpp.org.

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

<div dir=3D"ltr">On Friday, March 24, 2017 at 5:57:11 PM UTC-4, Sean Middle=
ditch wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">O=
n Thursday, March 23, 2017 at 9:38:19 AM UTC-7, Matthew Fioravante wrote:<b=
lockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-=
left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">1. Its too easy to a=
ccidentally use a moved from object by mistake<br></div></blockquote><div><=
br></div><div>This is a problem with C++&#39;s move semantics (e.g., non-de=
structive move and unspecific states). These problems have been discussed p=
lenty of times before, particularly in destructive-move threads.</div><div>=
<br></div><div>One solution in the works may be contract programming. Some =
of the proposals allow a function to set a post-condition state on an objec=
t which can be verified by a compiler or static analysis in a pre-condition=
.. e.g., unique_ptr might have something like:</div><div><br></div><div>=C2=
=A0 [[post_condition(src): empty]</div><div>=C2=A0 unique_ptr(unique_ptr&am=
p;&amp; src);</div><div><br></div><div>=C2=A0 [[pre_condition(this): !empty=
]</div><div>=C2=A0 unique_ptr::operator-&gt;();</div><div><br></div><div>Su=
ch a setup can further hypothetically address other issues like accidental =
dereferencing of default-constructed unique_ptrs. As well as a wide host of=
 other issues.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div dir=3D"ltr"><div>2. unique_ptr&lt;T&gt; and T* being different types=
 can cause pessimizations because of language rules.</div></div></blockquot=
e><div><br></div><div>I personally most see this as a problem caused by a l=
ack of generators, or more specifically at the lack of range concepts (whic=
h of course are in the works).</div><div><br></div><div>You usually don&#39=
;t want to require specifically a vector nor specifically a pointer of any =
kind. You want to return an object that can be enumerated to produce refere=
nces to T objects. The vector itself or unique_ptr vs raw pointers is an im=
plementation detail that callers should not have to care about.</div><div><=
br></div><div>With range concepts, this all still has to be a template of c=
ourse, but you don&#39;t have to over-worry about the specifics while using=
 the interface.</div><div><br></div><div>With generators, this can be abstr=
acted without templates (though perhaps at a runtime cost).</div><div><br><=
/div><div>Basically, you want to write something like:</div><div><br></div>=
<div>=C2=A0 iterable&lt;T&amp;&gt; foo::get_things() { return make_iterable=
(_things, [](auto&amp; p){ return *p; }); }<br></div><div><br></div><div></=
div></div></blockquote><div><br>That&#39;s a really bad tradeoff: type-eras=
ing performance plus the cost of filtering, all just to gain some increased=
 genericity. <br><br>But Boost.Range already has something like this: `<a h=
ref=3D"http://www.boost.org/doc/libs/1_63_0/libs/range/doc/html/range/refer=
ence/ranges/any_range.html">any_range</a>`, coupled with <a href=3D"http://=
www.boost.org/doc/libs/1_63_0/libs/range/doc/html/range/reference/adaptors/=
reference/transformed.html">transforming the input range by a function</a>.=
<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/136fc743-bc63-48c8-b1d5-dc4084dd13cf%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/136fc743-bc63-48c8-b1d5-dc4084dd13cf=
%40isocpp.org</a>.<br />

------=_Part_2293_1425852513.1490394351178--

------=_Part_2292_1276201536.1490394351178--

.


Author: Matthew Fioravante <fmatthew5876@gmail.com>
Date: Sat, 25 Mar 2017 10:00:23 -0700 (PDT)
Raw View
------=_Part_2432_1186240992.1490461223763
Content-Type: multipart/alternative;
 boundary="----=_Part_2433_1234684880.1490461223763"

------=_Part_2433_1234684880.1490461223763
Content-Type: text/plain; charset=UTF-8



On Friday, March 24, 2017 at 5:25:51 PM UTC-5, Nicol Bolas wrote:
>
> On Friday, March 24, 2017 at 5:57:11 PM UTC-4, Sean Middleditch wrote:
>>
>> On Thursday, March 23, 2017 at 9:38:19 AM UTC-7, Matthew Fioravante wrote:
>>>
>>> 1. Its too easy to accidentally use a moved from object by mistake
>>>
>>
>> This is a problem with C++'s move semantics (e.g., non-destructive move
>> and unspecific states). These problems have been discussed plenty of times
>> before, particularly in destructive-move threads.
>>
>> One solution in the works may be contract programming. Some of the
>> proposals allow a function to set a post-condition state on an object which
>> can be verified by a compiler or static analysis in a pre-condition. e.g.,
>> unique_ptr might have something like:
>>
>>   [[post_condition(src): empty]
>>   unique_ptr(unique_ptr&& src);
>>
>>   [[pre_condition(this): !empty]
>>   unique_ptr::operator->();
>>
>> Such a setup can further hypothetically address other issues like
>> accidental dereferencing of default-constructed unique_ptrs. As well as a
>> wide host of other issues.
>>
>>
>>> 2. unique_ptr<T> and T* being different types can cause pessimizations
>>> because of language rules.
>>>
>>
>> I personally most see this as a problem caused by a lack of generators,
>> or more specifically at the lack of range concepts (which of course are in
>> the works).
>>
>> You usually don't want to require specifically a vector nor specifically
>> a pointer of any kind. You want to return an object that can be enumerated
>> to produce references to T objects. The vector itself or unique_ptr vs raw
>> pointers is an implementation detail that callers should not have to care
>> about.
>>
>> With range concepts, this all still has to be a template of course, but
>> you don't have to over-worry about the specifics while using the interface.
>>
>> With generators, this can be abstracted without templates (though perhaps
>> at a runtime cost).
>>
>> Basically, you want to write something like:
>>
>>   iterable<T&> foo::get_things() { return make_iterable(_things, [](auto&
>> p){ return *p; }); }
>>
>>
> That's a really bad tradeoff: type-erasing performance plus the cost of
> filtering, all just to gain some increased genericity.
>
>
I agree that generic ranges are great and badly needed, but I don't think
they apply here.

You're actually not gaining anything here doing it this way. You're even
losing. The paradigm is backwards (generic outputs instead of inputs).

To achieve generic code support, Container only needs to return *something*
that looks like a range. The generic caller doesn't care at all what that
*something* actually is. An array_view<T> is a range. By returning a very
specific range type array_view<T>, you satisfy anyone writing generic code.
For free you also satisfy the specific case of someone who is only
interested in arrays. You can do everything on an array_view<T> that you
can on a generic range. Its easier to debug because you know the actual
type returned. By returning a generic object, all you're doing is throwing
away useful type information. Lets also not forget the horribly long
compiler error messages that will come when this is used wrong.

In terms of generic code, its better for inputs to be more generic, and
outputs to be more specific (while still fulfilling a generic concept).
Generic inputs minimizes the constraints on what I can pass into the API.
Specific outputs that match concepts don't provide any limitations, but
they can add optimization opportunities and compatibility with other API's
which aren't generic. If I don't need the extra information provided by
having a specific type, I can just erase it myself  when I pass it along to
the next generic API. The important point is I had the choice to do the
erasure on my end, instead of it being forced upon me by the Container
author's getThings().

The great thing about array_view<T> is that it gives you a level of
genericity (contiguous ranges), without the heavy handedness of templates.
Compile times are fast, no code bloat, out of line compilation. Its also
damn efficient.

--
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/0b40f2b6-bb90-4f98-b6fe-cc0ee0e0d76a%40isocpp.org.

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

<div dir=3D"ltr"><br><br>On Friday, March 24, 2017 at 5:25:51 PM UTC-5, Nic=
ol Bolas 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=
">On Friday, March 24, 2017 at 5:57:11 PM UTC-4, Sean Middleditch wrote:<bl=
ockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On Thursday, March 23=
, 2017 at 9:38:19 AM UTC-7, Matthew Fioravante wrote:<blockquote class=3D"g=
mail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;=
padding-left:1ex"><div dir=3D"ltr">1. Its too easy to accidentally use a mo=
ved from object by mistake<br></div></blockquote><div><br></div><div>This i=
s a problem with C++&#39;s move semantics (e.g., non-destructive move and u=
nspecific states). These problems have been discussed plenty of times befor=
e, particularly in destructive-move threads.</div><div><br></div><div>One s=
olution in the works may be contract programming. Some of the proposals all=
ow a function to set a post-condition state on an object which can be verif=
ied by a compiler or static analysis in a pre-condition. e.g., unique_ptr m=
ight have something like:</div><div><br></div><div>=C2=A0 [[post_condition(=
src): empty]</div><div>=C2=A0 unique_ptr(unique_ptr&amp;&amp; src);</div><d=
iv><br></div><div>=C2=A0 [[pre_condition(this): !empty]</div><div>=C2=A0 un=
ique_ptr::operator-&gt;();</div><div><br></div><div>Such a setup can furthe=
r hypothetically address other issues like accidental dereferencing of defa=
ult-constructed unique_ptrs. As well as a wide host of other issues.</div><=
div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-=
left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><d=
iv>2. unique_ptr&lt;T&gt; and T* being different types can cause pessimizat=
ions because of language rules.</div></div></blockquote><div><br></div><div=
>I personally most see this as a problem caused by a lack of generators, or=
 more specifically at the lack of range concepts (which of course are in th=
e works).</div><div><br></div><div>You usually don&#39;t want to require sp=
ecifically a vector nor specifically a pointer of any kind. You want to ret=
urn an object that can be enumerated to produce references to T objects. Th=
e vector itself or unique_ptr vs raw pointers is an implementation detail t=
hat callers should not have to care about.</div><div><br></div><div>With ra=
nge concepts, this all still has to be a template of course, but you don&#3=
9;t have to over-worry about the specifics while using the interface.</div>=
<div><br></div><div>With generators, this can be abstracted without templat=
es (though perhaps at a runtime cost).</div><div><br></div><div>Basically, =
you want to write something like:</div><div><br></div><div>=C2=A0 iterable&=
lt;T&amp;&gt; foo::get_things() { return make_iterable(_things, [](auto&amp=
; p){ return *p; }); }<br></div><div><br></div><div></div></div></blockquot=
e><div><br>That&#39;s a really bad tradeoff: type-erasing performance plus =
the cost of filtering, all just to gain some increased genericity. <br><br>=
</div></div></blockquote><div><br>I agree that generic ranges are great and=
 badly needed, but I don&#39;t think they apply here.<br><br>You&#39;re act=
ually not gaining anything here doing it this way. You&#39;re even losing. =
The paradigm is backwards (generic outputs instead of inputs).<br><br>To ac=
hieve generic code support, Container only needs to return *something* that=
 looks like a range. The generic caller doesn&#39;t care at all what that *=
something* actually is. An array_view&lt;T&gt; is a range. By returning a v=
ery specific range type array_view&lt;T&gt;, you satisfy anyone writing gen=
eric code. For free you also satisfy the specific case of someone who is on=
ly interested in arrays. You can do everything on an array_view&lt;T&gt; th=
at you can on a generic range. Its easier to debug because you know the act=
ual type returned. By returning a generic object, all you&#39;re doing is t=
hrowing away useful type information. Lets also not forget the horribly lon=
g compiler error messages that will come when this is used wrong.<br><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br><code>In terms of g=
eneric code, its better for inputs to be more generic, and outputs to be mo=
re specific (while still fulfilling a generic concept). Generic inputs mini=
mizes the constraints on what I can pass into the API. Specific outputs tha=
t match concepts don&#39;t provide any limitations, but they can add optimi=
zation opportunities and compatibility with other API&#39;s which aren&#39;=
t generic.</code> If I don&#39;t need the extra information provided by hav=
ing a specific type, I can just erase it myself=C2=A0 when I pass it along =
to the next generic API. The important point is I had the choice to do the =
erasure on my end, instead of it being forced upon me by the Container auth=
or&#39;s getThings().<br><br>The great thing about array_view&lt;T&gt; is t=
hat it gives you a level of genericity (contiguous ranges), without the hea=
vy handedness of templates. Compile times are fast, no code bloat, out of l=
ine compilation. Its also damn efficient.<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/0b40f2b6-bb90-4f98-b6fe-cc0ee0e0d76a%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/0b40f2b6-bb90-4f98-b6fe-cc0ee0e0d76a=
%40isocpp.org</a>.<br />

------=_Part_2433_1234684880.1490461223763--

------=_Part_2432_1186240992.1490461223763--

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Tue, 28 Mar 2017 14:22:43 -0400
Raw View
On 2017-03-23 12:38, Matthew Fioravante wrote:
> 2. Provide a specialized unique_vector<T*> which essentially operates like
> vector<unique_ptr<T>>, but exposes T* in its const interface.

See http://doc.qt.io/qt-5/qlist.html. Despite Marc Mutz' crusade against
them, I still tend to think that a container type that is like vector<T>
but stores its elements indirectly seems like it should be one of the
basic container types.

--
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/58DAA9F3.8070900%40gmail.com.

.