220 31727 <86aeb556-e0d7-4d68-b553-1b4163461473@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: Sean Middleditch <sean.middleditch@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: Complexities caused by using unique_ptr and move semantics
Date: Fri, 24 Mar 2017 14:57:11 -0700 (PDT)
Lines: 360
Approved: news@gmane.org
Message-ID: <86aeb556-e0d7-4d68-b553-1b4163461473@isocpp.org>
References: <46a85060-631b-49e5-94f3-ab07429d8085@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_856_1014739906.1490392631298"
X-Trace: blaine.gmane.org 1490392638 1758 195.159.176.226 (24 Mar 2017 21:57:18 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Fri, 24 Mar 2017 21:57:18 +0000 (UTC)
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCDODCNR2QPRBOFM23DAKGQEMAD3EBY@isocpp.org Fri Mar 24 22:57:12 2017
Return-path: <std-proposals+bncBCDODCNR2QPRBOFM23DAKGQEMAD3EBY@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-yw0-f198.google.com ([209.85.161.198])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCDODCNR2QPRBOFM23DAKGQEMAD3EBY@isocpp.org>)
	id 1crXCl-0007pf-4q
	for gclcip-std-proposals@m.gmane.org; Fri, 24 Mar 2017 22:57:07 +0100
Original-Received: by mail-yw0-f198.google.com with SMTP id h11sf4660146ywa.5
        for <gclcip-std-proposals@m.gmane.org>; Fri, 24 Mar 2017 14:57:13 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=EoXg6EeAhOaXnh3E5GI1hH8a/hnvUJ5uXk1w20OPHPs=;
        b=IpM3KwLdPGgg/7Woxbadma7j2tAEmCiuyE0FK5nHVw0tNf3uOHVr5UJo4ZKUF3ot8z
         ZxuS1mSTGsUkCfogTm0YSNhxl6Y//CrpaJUfV9ApQ5z28RL7JEjRyCkIz+UiECvN7rq0
         ZUScWoP81SOIacq/UPtmlbUz1Re1lPn030woeDyymAfiyLIUGlgZKjgHeveLIDbxPf1W
         aVgGdyokijuPM/22WSrKUHeCn64hGcxx+VWgQ1y33Sas4TyQ4vd9odwfGvJGLvBcjYUw
         DeR7lBX1gammp5j0AgqezHA+VU2Nr2a0oCKxyqr/KR3XJyw6clbm+3XG+SpglJfmv0Lq
         7GCw==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=EoXg6EeAhOaXnh3E5GI1hH8a/hnvUJ5uXk1w20OPHPs=;
        b=qPvH7OL0QE2ho871hN4T8ffRpa7+3/CNbxCDZG8j1yizCrsFmOXj7d5NL6NfCYNmX/
         5jUPrDTCm4HA2aaVX1wcFOukJ6O3BaEmoVR3cidD+bF9Z2n/DztVoQfNWrHSICdvZdlt
         IMUK8/vGt8qjN15dJmd9EpGA1U7ERoTSTJvCa7xAvF2I45cJ6c+41r1INBuc5iQKkPLM
         HV7XStzlp2Br5gdWglVudVvovCmisGwWG1/4FnbXD+J8wlIx9ZK3h21NqAaXLidGyd7d
         m4VfahvopbolNDW2AM6I8fDuDAOKagm33JO0kPVmt1TZF1qYnO+3E8bWH2dt6H2nczF5
         eDDQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:date:from:to:message-id:in-reply-to:references
         :subject:mime-version:x-original-sender:reply-to:precedence
         :mailing-list:list-id:x-spam-checked-in-group:list-post:list-help
         :list-archive:list-subscribe:list-unsubscribe;
        bh=EoXg6EeAhOaXnh3E5GI1hH8a/hnvUJ5uXk1w20OPHPs=;
        b=KwIVNLonOn1XZ/rgwCrKaoKDpj8JIPfRBMTdWa3LPmpZyf8xNLyJ39cZEZUoTX96QX
         pI9ZPiLXyLMnPuqH6nVxnVliFwYKAAEwEabVVhM59jBmZuc/y7oewY1ywAFoxo9CBBeL
         6H1PSgjNhS+rBxIHphBurcyaA9Yi7Uo0+FO8/Uei9XsdJ3wi54bNsmgrQLmF/Yq/E7Iv
         FQboORfGMh57KMl7L+/gf7jIHewPbf83mAgEs4jMRnRf+z0LykwCyBkwgxi0CY1kELgX
         XWkAiTUoNU3tdrlOyG3magUIZDPSMWclMjPordGUBS+6KODtA8mx3p96lBWjP0a0f7w6
         g8ow==
X-Gm-Message-State: AFeK/H0PJIKABB6IPpWkNcw98Uvkwk2OcL+jbj/nEgFbYe+xHVwf+Q9VyIl1JxIX3sPRQg==
X-Received: by 10.129.111.65 with SMTP id k62mr3451784ywc.8.1490392632752;
        Fri, 24 Mar 2017 14:57:12 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.157.11.3 with SMTP id a3ls8169040ota.23.gmail; Fri, 24 Mar
 2017 14:57:11 -0700 (PDT)
X-Received: by 10.157.15.162 with SMTP id d31mr1035037otd.0.1490392631910;
        Fri, 24 Mar 2017 14:57:11 -0700 (PDT)
In-Reply-To: <46a85060-631b-49e5-94f3-ab07429d8085@isocpp.org>
X-Original-Sender: Sean.Middleditch@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:31727
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/31727>

------=_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--

.
