Topic: inserting an rvalue (was Adding 'extract' method
Author: David Krauss <potswa@gmail.com>
Date: Sun, 17 Nov 2013 17:46:24 +0800
Raw View
This is a multi-part message in MIME format.
--------------070008080901030907000702
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
On 11/17/13 3:29 PM, xavi wrote:
> In some cases that's possible, but as Jared pointed out, for getting a
> pointer out of std::set it must be a member function, because it's not
> possible to do it with the current interface.
This is essentially true, but depending how you look there could be a
loophole. The implementation could actually perform a const_cast in the
free function without any friendship to the class, because the issue is
whether the const_cast is well-formed (I'm not sure; it depends on
placement new semantics) and whether the moved-from value affects the
remove(iterator) operation (the container must support this). But tying
the function closer to the class would probably be cleaner specification.
> No they don't. map::insert doesn't move from its argument unless it is
> actually inserted. And neither does set::insert. The following code
>
> std::set<std::unique_ptr<int>> my_set;
> int *p=new int;
> std::unique_ptr<int> a(p);
> std::unique_ptr<int> b(p);
> my_set.insert(std::move(a));
> my_set.insert(std::move(b));
> std::cout << (bool)a << (bool)b << "\n";
>
> prints again 01, which means that the second insertion doesn't move from
> the object, since it's already there.
Hmm, I get 01 from GCC but 00 from Clang 3.2.
The spec I was referring to turns out to be specific to std::map. From
23.4.4.4:
> Otherwisex is considered to be an rvalue as it is converted to value_type and
inserted into the map.
C++ International Standard Converting a tuple or pair of references to
value_type would already doom the object, but actually this language is
unspecific as to whether that happens if the insertion doesn't occur.
In the case of std::set there is no spec for insert besides the generic
Container requirements, and it's an indeterminate moved-from value which
explains the difference between GCC and Clang.
> And with perfect forwarding it can perform the lookup without copying it.
> I think insert works perfectly well as is now.
Perfect forwarding isn't the problem per se, but that the function needs
to convert its argument because perfect forwarding disables implicit
conversion within the caller. That is why the spec says that an rvalue
argument "is converted to value_type". To be sure when they are the same
type that does not require an xvalue-to-prvalue move construction,
neither is that forbidden, and avoiding it would require writing a
special case.
The other reason this is broken is that such conversions canonically
occur at the call site. If the conversion were only accessible by the
caller such as due to friendship, an explicit conversion would be needed
which is unusual. It's doesn't contravene the Container::insert()
requirements, though, which are only defined in terms of a value_type
argument.
I suppose there must be a reason set and map are different here, so I
have some homework to do before having a really valid complaint.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
--------------070008080901030907000702
Content-Type: text/html; charset=ISO-8859-1
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div class="moz-cite-prefix">On 11/17/13 3:29 PM, xavi wrote:<br>
</div>
<blockquote
cite="mid:CAOUeGfvwNwt=4M9Yk5xe_uY2GADMuW2YU0vYQXChj763BX_FzQ@mail.gmail.com"
type="cite">In some cases that's possible, but as Jared pointed
out, for getting a
pointer out of std::set it must be a member function, because it's
not
possible to do it with the current interface.</blockquote>
<br>
This is essentially true, but depending how you look there could be
a loophole. The implementation could actually perform a const_cast
in the free function without any friendship to the class, because
the issue is whether the const_cast is well-formed (I'm not sure; it
depends on placement new semantics) and whether the moved-from value
affects the remove(iterator) operation (the container must support
this). But tying the function closer to the class would probably be
cleaner specification.<br>
<br>
<blockquote
cite="mid:CAOUeGfvwNwt=4M9Yk5xe_uY2GADMuW2YU0vYQXChj763BX_FzQ@mail.gmail.com"
type="cite">
<pre wrap="">No they don't. map::insert doesn't move from its argument unless it is
actually inserted. And neither does set::insert. The following code
std::set<std::unique_ptr<int>> my_set;
int *p=new int;
std::unique_ptr<int> a(p);
std::unique_ptr<int> b(p);
my_set.insert(std::move(a));
my_set.insert(std::move(b));
std::cout << (bool)a << (bool)b << "\n";
prints again 01, which means that the second insertion doesn't move from
the object, since it's already there.</pre>
</blockquote>
<br>
Hmm, I get 01 from GCC but 00 from Clang 3.2.<br>
<br>
The spec I was referring to turns out to be specific to std::map.
From 23.4.4.4:
<div class="page" title="Page 807">
<div class="layoutArea">
<div class="column">
<p><span style="font-size: 10.000000pt; font-family:
'LMRoman10'">> Otherwise </span><span
style="font-size: 10.000000pt; font-family:
'LMTypewriter10'">x </span><span style="font-size:
10.000000pt; font-family: 'LMRoman10'">is considered to be
an rvalue as it is converted to </span><span
style="font-size: 10.000000pt; font-family:
'LMTypewriter10'">value_type </span><span
style="font-size: 10.000000pt; font-family: 'LMRoman10'">and
inserted into the </span><span style="font-size:
10.000000pt; font-family: 'LMTypewriter10'">map</span><span
style="font-size: 10.000000pt; font-family: 'LMRoman10'">.
</span></p>
</div>
</div>
</div>
<title>C++ International Standard</title>
Converting a tuple or pair of references to value_type would already
doom the object, but actually this language is unspecific as to
whether that happens if the insertion doesn't occur.<br>
<br>
In the case of std::set there is no spec for insert besides the
generic Container requirements, and it's an indeterminate moved-from
value which explains the difference between GCC and Clang.<br>
<br>
<blockquote
cite="mid:CAOUeGfvwNwt=4M9Yk5xe_uY2GADMuW2YU0vYQXChj763BX_FzQ@mail.gmail.com"
type="cite">
<pre wrap="">And with perfect forwarding it can perform the lookup without copying it.</pre>
</blockquote>
<blockquote
cite="mid:CAOUeGfvwNwt=4M9Yk5xe_uY2GADMuW2YU0vYQXChj763BX_FzQ@mail.gmail.com"
type="cite">
<pre wrap="">I think insert works perfectly well as is now.</pre>
</blockquote>
<br>
Perfect forwarding isn't the problem per se, but that the function
needs to convert its argument because perfect forwarding disables
implicit conversion within the caller. That is why the spec says
that an rvalue argument "<span style="font-size: 10.000000pt;
font-family: 'LMRoman10'">is converted to </span><span
style="font-size: 10.000000pt; font-family: 'LMTypewriter10'">value_type"</span>.
To be sure when they are the same type that does not require an
xvalue-to-prvalue move construction, neither is that forbidden, and
avoiding it would require writing a special case.<br>
<br>
The other reason this is broken is that such conversions canonically
occur at the call site. If the conversion were only accessible by
the caller such as due to friendship, an explicit conversion would
be needed which is unusual. It's doesn't contravene the
Container::insert() requirements, though, which are only defined in
terms of a value_type argument.<br>
<br>
I suppose there must be a reason set and map are different here, so
I have some homework to do before having a really valid complaint.<br>
<br>
</body>
</html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href="http://groups.google.com/a/isocpp.org/group/std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/</a>.<br />
--------------070008080901030907000702--
.