|
3 | 3 |
|
4 | 4 | <issue num="4251" status="New"> |
5 | 5 | <title>Move assignment for `indirect` unnecessarily requires copy construction</title> |
6 | | -<section><sref ref="[indirect.asgn]"/></section> |
| 6 | +<section> |
| 7 | +<sref ref="[indirect.assign]"/> |
| 8 | +<sref ref="[polymorphic.assign]"/> |
| 9 | +</section> |
7 | 10 | <submitter>Jonathan Wakely</submitter> |
8 | 11 | <date>01 May 2025</date> |
9 | 12 | <priority>1</priority> |
@@ -46,15 +49,14 @@ Set priority to 1 after reflector poll. |
46 | 49 | Similar change needed for `std::polymorphic`. |
47 | 50 | </p> |
48 | 51 |
|
49 | | -</discussion> |
50 | 52 |
|
51 | | -<resolution> |
| 53 | +<superseded> |
52 | 54 | <p> |
53 | 55 | This wording is relative to <paper num="N5008"/>. |
54 | 56 | </p> |
55 | 57 | <ol> |
56 | 58 |
|
57 | | -<li><p>Modify <sref ref="[indirect.asgn]"/> as indicated:</p> |
| 59 | +<li><p>Modify <sref ref="[indirect.assign]"/> as indicated:</p> |
58 | 60 | <blockquote> |
59 | 61 | <pre><code> |
60 | 62 | constexpr indirect& operator=(indirect&& other) |
@@ -122,6 +124,153 @@ the allocator in `*this` is replaced with a copy of the allocator in `other`. |
122 | 124 | </blockquote> |
123 | 125 | </blockquote> |
124 | 126 | </li> |
| 127 | +</ol> |
| 128 | +</superseded> |
| 129 | + |
| 130 | +<note>2025-11-03; Tomasz provides wording.</note> |
| 131 | +</discussion> |
| 132 | + |
| 133 | +<resolution> |
| 134 | +<p> |
| 135 | +This wording is relative to <paper num="N5008"/>. |
| 136 | +</p> |
| 137 | +<ol> |
| 138 | + |
| 139 | +<li><p>Modify <sref ref="[polymorphic.assign]"/> as indicated:</p> |
| 140 | +<blockquote> |
| 141 | +<pre><code> |
| 142 | +constexpr indirect& operator=(indirect&& other) |
| 143 | + noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || |
| 144 | + allocator_traits<Allocator>::is_always_equal::value); |
| 145 | +</code></pre> |
| 146 | +<blockquote> |
| 147 | +<p> |
| 148 | +-5- <i>Mandates</i>: |
| 149 | +<ins> |
| 150 | +If |
| 151 | +<code>allocator_traits<Allocator>::propagate_on_container_move_assignment::value</code> |
| 152 | +is `false` |
| 153 | +and |
| 154 | +<code>allocator_traits<Allocator>::is_always_equal::value</code> |
| 155 | +is `false`, |
| 156 | +</ins> |
| 157 | +<code>is_<del>copy</del><ins>move</ins>_constructible_t<T></code> is `true`. |
| 158 | +</p> |
| 159 | +<p> |
| 160 | +-6- <i>Effects</i>: |
| 161 | +If `addressof(other) == this` is `true`, there are no effects. |
| 162 | +Otherwise: |
| 163 | +<ol style="list-style-type:none"> |
| 164 | +<li>(6.1) — |
| 165 | +The allocator needs updating if |
| 166 | +<code>allocator_traits<Allocator>::propagate_on_container_move_assignment::value</code> |
| 167 | +is `true`. |
| 168 | +</li> |
| 169 | +<li>(6.2) — |
| 170 | +If `other` is valueless, `*this` becomes valueless<del> and the owned object |
| 171 | +in `*this`, if any, is destroyed using |
| 172 | +<code>allocator_traits<Allocator>::destroy</code> |
| 173 | +and then the storage is deallocated</del>. |
| 174 | +</li> |
| 175 | +<li>(6.3) — |
| 176 | +Otherwise, |
| 177 | +<ins>if the allocator needs updating or</ins> |
| 178 | +if <code><i>alloc</i> == other.<i>alloc</i></code> is `true`, |
| 179 | +<del> |
| 180 | +swaps the owned objects in `*this` and `other`; |
| 181 | +the owned object in `other`, if any, is then destroyed using |
| 182 | +<code>allocator_traits<Allocator>::destroy</code> |
| 183 | +and then the storage is deallocated |
| 184 | +</del> |
| 185 | +<ins>`*this` takes ownership of the owned object of `other`</ins>. |
| 186 | +</li> |
| 187 | +<li>(6.4) — |
| 188 | +Otherwise, constructs a new owned object with the owned object of `other` |
| 189 | +as the argument as an rvalue, using <del>either</del> the allocator in `*this` |
| 190 | +<del>or the allocator in `other` if the allocator needs updating</del>. |
| 191 | +</li> |
| 192 | +<li>(6.5) — |
| 193 | +The previously owned object in `*this`, if any, is destroyed using |
| 194 | +<code>allocator_traits<Allocator>::destroy</code> |
| 195 | +and then the storage is deallocated. |
| 196 | +</li> |
| 197 | +<li>(6.6) — |
| 198 | +If the allocator needs updating, |
| 199 | +the allocator in `*this` is replaced with a copy of the allocator in `other`. |
| 200 | +</li> |
| 201 | +</ol> |
| 202 | +</p> |
| 203 | +<p>-7- <i>Postcondition</i>: `other` is valueless.</p> |
| 204 | +</blockquote> |
| 205 | +</blockquote> |
| 206 | +</li> |
| 207 | + |
| 208 | +<li><p>Modify <sref ref="[polymorphic.asgn]"/> as indicated:</p> |
| 209 | +<blockquote> |
| 210 | +<pre><code> |
| 211 | +constexpr polymorphic& operator=(polymorphic&& other) |
| 212 | + noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || |
| 213 | + allocator_traits<Allocator>::is_always_equal::value); |
| 214 | +</code></pre> |
| 215 | +<blockquote> |
| 216 | +<p> |
| 217 | +-5- <i>Mandates</i>: |
| 218 | +If |
| 219 | +<ins> |
| 220 | +<code>allocator_traits<Allocator>::propagate_on_container_move_assignment::value</code> |
| 221 | +is `false` |
| 222 | +and |
| 223 | +</ins> |
| 224 | +<code>allocator_traits<Allocator>::is_always_equal::value</code> |
| 225 | +is `false`, |
| 226 | +`T` is complete type. |
| 227 | +</p> |
| 228 | +<p> |
| 229 | +-6- <i>Effects</i>: |
| 230 | +If `addressof(other) == this` is `true`, there are no effects. |
| 231 | +Otherwise: |
| 232 | +<ol style="list-style-type:none"> |
| 233 | +<li>(6.1) — |
| 234 | +The allocator needs updating if |
| 235 | +<code>allocator_traits<Allocator>::propagate_on_container_move_assignment::value</code> |
| 236 | +is `true`. |
| 237 | +</li> |
| 238 | +<li><ins>(6.?) — If `other` is valueless, `*this` becomes valueless.</ins></li> |
| 239 | +<li>(6.2) — |
| 240 | +<ins>Otherwise, if the allocator needs updating or</ins><del>If</del> |
| 241 | +<code><i>alloc</i> == other.<i>alloc</i></code> is `true`, |
| 242 | +<del> |
| 243 | +swaps the owned objects in `*this` and `other`; |
| 244 | +the owned object in `other`, if any, is then destroyed using |
| 245 | +<code>allocator_traits<Allocator>::destroy</code> |
| 246 | +and then the storage is deallocated |
| 247 | +</del> |
| 248 | +<ins>`*this` takes ownership of the owned object of `other`</ins>. |
| 249 | +</li> |
| 250 | +<li>(6.3) — |
| 251 | +<del>Otherwise, if `alloc != other.alloc` is `true`; if `other` is not valueless, |
| 252 | +a new owned object is constructed in `*this` using <tt>allocator_traits::construct</tt> |
| 253 | +with the owned object from</del> |
| 254 | +<ins>Otherwise, constructs a new owned object with the owned object of</ins> |
| 255 | +`other` as the argument as an rvalue, using <del>either</del> the allocator in `*this` |
| 256 | +<del>or the allocator in `other` if the allocator needs updating</del>. |
| 257 | +</li> |
| 258 | +<li>(6.4) — |
| 259 | +The previously owned object in `*this`, if any, is destroyed using |
| 260 | +<code>allocator_traits<Allocator>::destroy</code> |
| 261 | +and then the storage is deallocated. |
| 262 | +</li> |
| 263 | +<li>(6.5) — |
| 264 | +If the allocator needs updating, |
| 265 | +the allocator in `*this` is replaced with a copy of the allocator in `other`. |
| 266 | +</li> |
| 267 | +</ol> |
| 268 | +</p> |
| 269 | +[…] |
| 270 | +</blockquote> |
| 271 | +</blockquote> |
| 272 | +</li> |
| 273 | + |
125 | 274 | </ol> |
126 | 275 | </resolution> |
127 | 276 |
|
|
0 commit comments