<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2023-10-15" />
  <title>Relocation Within Containers</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.csl-block{margin-left: 1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Relocation Within
Containers</h1>
<h3 class="subtitle" style="text-align:center">Enabling trivial
relocation for std::vector</h3>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2959R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2023-10-15</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      Library Evolution Working Group<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Alisdair Meredith<br>&lt;<a href="mailto:ameredith1@bloomberg.net" class="email">ameredith1@bloomberg.net</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">1</span> Abstract<span></span></a></li>
<li><a href="#rev.hist" id="toc-rev.hist"><span class="toc-section-number">2</span> Revision history<span></span></a>
<ul>
<li><a href="#r0-october-2023-pre-kona-mailing" id="toc-r0-october-2023-pre-kona-mailing">R0: October 2023 (pre-Kona
mailing)<span></span></a></li>
</ul></li>
<li><a href="#intro" id="toc-intro"><span class="toc-section-number">3</span> Introduction<span></span></a></li>
<li><a href="#eg.motivation" id="toc-eg.motivation"><span class="toc-section-number">4</span> Motivating Examples<span></span></a>
<ul>
<li><a href="#eg.listvlist" id="toc-eg.listvlist"><span class="toc-section-number">4.1</span>
<code class="sourceCode default">list</code> vs
<code class="sourceCode default">vector</code><span></span></a></li>
<li><a href="#eg.vectorvvector" id="toc-eg.vectorvvector"><span class="toc-section-number">4.2</span>
<code class="sourceCode default">vector</code> vs
<code class="sourceCode default">vector</code><span></span></a></li>
</ul></li>
<li><a href="#related-lwg-issues" id="toc-related-lwg-issues"><span class="toc-section-number">5</span> Related LWG
issues<span></span></a></li>
<li><a href="#current-specification" id="toc-current-specification"><span class="toc-section-number">6</span>
Current Specification<span></span></a>
<ul>
<li><a href="#elements-are-created-using-allocator_traitsconstruct" id="toc-elements-are-created-using-allocator_traitsconstruct"><span class="toc-section-number">6.1</span> Elements are created using
<code class="sourceCode default">allocator_traits::construct</code><span></span></a></li>
<li><a href="#elements-are-replaced-using-move-assignment" id="toc-elements-are-replaced-using-move-assignment"><span class="toc-section-number">6.2</span> Elements are replaced using
move-assignment<span></span></a></li>
</ul></li>
<li><a href="#concerns" id="toc-concerns"><span class="toc-section-number">7</span> Concerns<span></span></a>
<ul>
<li><a href="#replacing-elements-by-move-assignment-rather-than-move-construction" id="toc-replacing-elements-by-move-assignment-rather-than-move-construction"><span class="toc-section-number">7.1</span> Replacing elements by
move-assignment rather than move-construction<span></span></a></li>
<li><a href="#allocators-may-care-about-element-identity" id="toc-allocators-may-care-about-element-identity"><span class="toc-section-number">7.2</span> Allocators may care about element
identity<span></span></a></li>
<li><a href="#strong-exception-safety-guarantee-may-be-broken" id="toc-strong-exception-safety-guarantee-may-be-broken"><span class="toc-section-number">7.3</span> Strong exception safety guarantee
may be broken<span></span></a></li>
<li><a href="#supporting-trivial-optimizations" id="toc-supporting-trivial-optimizations"><span class="toc-section-number">7.4</span> Supporting trivial
optimizations<span></span></a></li>
<li><a href="#relocation-creates-objects-just-like-the-uninitialized-standard-algorithms" id="toc-relocation-creates-objects-just-like-the-uninitialized-standard-algorithms"><span class="toc-section-number">7.5</span> Relocation creates objects just
like the <code class="sourceCode default">uninitialized</code> standard
algorithms<span></span></a></li>
</ul></li>
<li><a href="#proposed-changes" id="toc-proposed-changes"><span class="toc-section-number">8</span> Proposed Changes<span></span></a>
<ul>
<li><a href="#new-type-trait-container_replace_with_assignment" id="toc-new-type-trait-container_replace_with_assignment"><span class="toc-section-number">8.1</span> New type trait: <code class="sourceCode default">container_replace_with_assignment</code><span></span></a></li>
<li><a href="#new-non-static-member-function-allocator_traitsrelocate" id="toc-new-non-static-member-function-allocator_traitsrelocate"><span class="toc-section-number">8.2</span> New non-static member function:
<code class="sourceCode default">allocator_traits::relocate</code><span></span></a></li>
<li><a href="#preferred-formula-for-allocator_traitsrelocate" id="toc-preferred-formula-for-allocator_traitsrelocate"><span class="toc-section-number">8.3</span> Preferred formula for
<code class="sourceCode default">allocator_traits::relocate</code><span></span></a></li>
<li><a href="#new-cpp17requirements-for-internal-relocation-in-a-block-container" id="toc-new-cpp17requirements-for-internal-relocation-in-a-block-container"><span class="toc-section-number">8.4</span> New <em>Cpp17Requirements</em> for
internal relocation in a block container<span></span></a></li>
<li><a href="#worked-example" id="toc-worked-example"><span class="toc-section-number">8.5</span> Worked
example<span></span></a></li>
</ul></li>
<li><a href="#optional-breaking-changes" id="toc-optional-breaking-changes"><span class="toc-section-number">9</span> Optional Breaking
Changes<span></span></a>
<ul>
<li><a href="#fixing-vectortupleint" id="toc-fixing-vectortupleint"><span class="toc-section-number">9.1</span> Fixing <code class="sourceCode default">vector&lt;tuple&lt;int&amp;&gt;&gt;</code><span></span></a></li>
<li><a href="#fixing-element-types-using-allocators-that-do-not-propagate-on-move-assignment" id="toc-fixing-element-types-using-allocators-that-do-not-propagate-on-move-assignment"><span class="toc-section-number">9.2</span> Fixing element types using
allocators that do not propagate on move
assignment<span></span></a></li>
</ul></li>
<li><a href="#addressing-objections" id="toc-addressing-objections"><span class="toc-section-number">10</span> Addressing
Objections<span></span></a>
<ul>
<li><a href="#abi-breakage" id="toc-abi-breakage"><span class="toc-section-number">10.1</span> ABI
breakage<span></span></a></li>
<li><a href="#breaking-changes-of-behavior" id="toc-breaking-changes-of-behavior"><span class="toc-section-number">10.2</span> Breaking changes of
behavior<span></span></a></li>
<li><a href="#potential-for-a-negative-impact-on-runtime-performance" id="toc-potential-for-a-negative-impact-on-runtime-performance"><span class="toc-section-number">10.3</span> Potential for a negative impact
on runtime performance<span></span></a></li>
<li><a href="#container-functions-like-stderase-retain-the-original-problems" id="toc-container-functions-like-stderase-retain-the-original-problems"><span class="toc-section-number">10.4</span> Container functions like
<code class="sourceCode default">std::erase</code> retain the original
problems<span></span></a></li>
</ul></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">11</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">12</span> References<span></span></a></li>
</ul>
</div>
<!-- RENDER AS html AS THE COMPARISON TABLES RENDER BADLY AS pdf -->
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<!-- NEEDS AN UPDATE, PAPER IS BIGGER, MORE CUSTOMIZATION POINTS -->
<p>The <em>Cpp17ContainerRequirements</em>, in conjunction with
<code class="sourceCode default">std::allocator_traits</code>, are
intended to support a wide variety of allocator behavior. Much of the
flexibility of <code class="sourceCode default">allocator_traits</code>
was modeled on support that would be needed for stateful allocators like
<code class="sourceCode default">std::pmr::polymorphic_allocator</code>.
This paper examines how the current requirements and traits fall short
when containers must internally relocate elements, and proposes a fix in
the form of a new optional customization point,
<code class="sourceCode default">allocator_traits::relocate</code>.</p>
<h1 data-number="2" id="rev.hist"><span class="header-section-number">2</span> Revision history<a href="#rev.hist" class="self-link"></a></h1>
<!-- PRE-PRINT --- THIS DOCUMENT WILL BE FINALIZED FOR THE OCTOBER 2023 MAILING -->
<h2 class="unnumbered" id="r0-october-2023-pre-kona-mailing">R0: October
2023 (pre-Kona mailing)<a href="#r0-october-2023-pre-kona-mailing" class="self-link"></a></h2>
<ul>
<li>Initial draft of this paper.</li>
</ul>
<h1 data-number="3" id="intro"><span class="header-section-number">3</span> Introduction<a href="#intro" class="self-link"></a></h1>
<p>The standard library informally has two different kinds of
containers, which we will call <em>node-based containers</em> and
<em>block-based containers</em> in this paper. A node-based container
typically manages each element in a separately allocated node, that
contains additional bookkeeping information such as pointers to adjacent
nodes in that data structure; examples include
<code class="sourceCode default">std::list</code> and
<code class="sourceCode default">std::map</code>. A <em>block-based</em>
container manages multiple elements in one or more blocks of
contiguously allocated memory; examples include
<code class="sourceCode default">std::vector</code> and
<code class="sourceCode default">std::deque</code>.</p>
<p>As additional vocabulary we will talk about <em>elements</em>
denoting the objects owned and managed by a container, and
<em>values</em> that are the salient state of objects (elements) stored
in a container. Containers manipulate elements, while they expose the
values of those elements to the outside world, such as through iterators
for the Standard Library algorithms. By inference, algorithms, views,
and ranges operate on values, not elements, unless they also manage the
lifetime of the objects they are supplied.</p>
<p>The distinction between element and value is typically academic in
the majority of cases. This paper addresses those occasions where the
difference matters, and how well, or badly, the standard library
responds. In particular, that distinction becomes a significant concern
when seeking to apply optimizations from the core language proposal for
<em>trivial relocatability</em> (<span class="citation" data-cites="P2786R2">[<a href="#ref-P2786R2" role="doc-biblioref">P2786R2</a>]</span>).</p>
<p>The second goal of this paper serves as an adjunct to <span class="citation" data-cites="P2786R2">[<a href="#ref-P2786R2" role="doc-biblioref">P2786R2</a>]</span>, extending the Standard Library
to provide better support for optimizing the use of trivially
relocatable types. The two goals are placed in the same paper to best
handle their interaction in the semantics and optimization of
block-based containers. It would be simple to move the pure library
extensions of the second goal into a separate paper if preferred.</p>
<h1 data-number="4" id="eg.motivation"><span class="header-section-number">4</span> Motivating Examples<a href="#eg.motivation" class="self-link"></a></h1>
<p>We will use <code class="sourceCode default">std::vector</code> as a
familiar proxy for block-based containers, and
<code class="sourceCode default">std::list</code> as a proxy for
node-based sequence containers. Below are a couple of motivating example
programs using
<code class="sourceCode default">tuple&lt;int &amp;&gt;</code> as the
element type, which will expose the subtle, but important, differences
between an element and a value.</p>
<p>When constructed
<code class="sourceCode default">tuple&lt;int &amp;&gt;</code> binds its
reference member to the same object as the constructor argument; however
on assignment
<code class="sourceCode default">tuple&lt;int &amp;&gt;</code> assigns
through its original reference rather than rebinding to the argument.
This is an intentional feature of the
<code class="sourceCode default">tuple</code> API to support the
<code class="sourceCode default">std::tie</code> interface<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p>
<p>The current behavior when replacing elements in a vector is to use
assignment whereas under our proposal this specific example would
effectively rebind the references as-if by construction.</p>
<h2 data-number="4.1" id="eg.listvlist"><span class="header-section-number">4.1</span>
<code class="sourceCode default">list</code> vs
<code class="sourceCode default">vector</code><a href="#eg.listvlist" class="self-link"></a></h2>
<p>Demonstrating inconsistent behavior between containers.
<code class="sourceCode default">std::list</code> and
<code class="sourceCode default">std::vector</code> will give different
results on the last statement below for an otherwise identical program.
We believe that difference in behavior is surprising other than in
hindsight, and suggest that
<code class="sourceCode default">std::vector</code> should behave the
same as <code class="sourceCode default">std::list</code> in C++26,
giving consistent but backwards-incompatible behavior.</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong><code class="sourceCode default">std::list</code></strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode default">std::vector</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;tuple&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;list&gt;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_move_assignable_v<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;)</span>;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_move_assignable_v<span class="op">&lt;</span>std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;&gt;)</span>;</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> a <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> b <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> c <span class="op">=</span> <span class="dv">3</span>;</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>list<span class="op">&lt;</span>std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;&gt;</span> x;</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>emplace_back<span class="op">(</span>a<span class="op">)</span>;</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>emplace_back<span class="op">(</span>b<span class="op">)</span>;</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>emplace_back<span class="op">(</span>c<span class="op">)</span>;</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;a:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> a <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>                            <span class="co">// 1</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;b:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> b <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>                            <span class="co">// 2</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;c:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> c <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;                           <span class="co">// 3</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="kw">const</span> mid <span class="op">=</span> std<span class="op">::</span>next<span class="op">(</span>x<span class="op">.</span>begin<span class="op">())</span>;</span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;x[0]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>front<span class="op">())</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>    <span class="co">// 1</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;x[1]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(*</span>mid<span class="op">)</span>      <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>    <span class="co">// 2</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;x[2]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>back<span class="op">())</span>  <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;   <span class="co">// 3</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>erase<span class="op">(</span>mid<span class="op">)</span>;</span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;x[0]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>front<span class="op">())</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>    <span class="co">// 1</span></span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;x[1]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>back<span class="op">())</span>  <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;   <span class="co">// 3</span></span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a>    b <span class="op">=</span> <span class="dv">4</span>;</span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a>    c <span class="op">=</span> <span class="dv">5</span>;</span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;x[0]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>front<span class="op">())</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>    <span class="co">// 1</span></span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;x[1]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>back<span class="op">())</span>  <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;   <span class="co">// 5</span></span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;tuple&gt;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;vector&gt;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_move_assignable_v<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;)</span>;</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_move_assignable_v<span class="op">&lt;</span>std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;&gt;)</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> a <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> b <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> c <span class="op">=</span> <span class="dv">3</span>;</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;&gt;</span> x;</span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>emplace_back<span class="op">(</span>a<span class="op">)</span>;</span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>emplace_back<span class="op">(</span>b<span class="op">)</span>;</span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>emplace_back<span class="op">(</span>c<span class="op">)</span>;</span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;a:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> a <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>                            <span class="co">// 1</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;b:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> b <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>                            <span class="co">// 2</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;c:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> c <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;                           <span class="co">// 3</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="kw">const</span> mid <span class="op">=</span> std<span class="op">::</span>next<span class="op">(</span>x<span class="op">.</span>begin<span class="op">())</span>;</span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;x[0]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>front<span class="op">())</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>    <span class="co">// 1</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;x[1]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(*</span>mid<span class="op">)</span>      <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>    <span class="co">// 2</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;x[2]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>back<span class="op">())</span>  <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;   <span class="co">// 3</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>erase<span class="op">(</span>mid<span class="op">)</span>;</span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;x[0]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>front<span class="op">())</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>    <span class="co">// 1</span></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;x[1]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>back<span class="op">())</span>  <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;   <span class="co">// 3</span></span>
<span id="cb2-34"><a href="#cb2-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-35"><a href="#cb2-35" aria-hidden="true" tabindex="-1"></a>    b <span class="op">=</span> <span class="dv">4</span>;</span>
<span id="cb2-36"><a href="#cb2-36" aria-hidden="true" tabindex="-1"></a>    c <span class="op">=</span> <span class="dv">5</span>;</span>
<span id="cb2-37"><a href="#cb2-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-38"><a href="#cb2-38" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;x[0]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>front<span class="op">())</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>    <span class="co">// 1</span></span>
<span id="cb2-39"><a href="#cb2-39" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&lt;</span> <span class="st">&quot;x[1]:</span><span class="sc">\t</span><span class="st">&quot;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>x<span class="op">.</span>back<span class="op">())</span>  <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;   <span class="co">// <span class="rm" style="color: #bf0303"><del>4</del></span></span></span>
<span id="cb2-40"><a href="#cb2-40" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<h2 data-number="4.2" id="eg.vectorvvector"><span class="header-section-number">4.2</span>
<code class="sourceCode default">vector</code> vs
<code class="sourceCode default">vector</code><a href="#eg.vectorvvector" class="self-link"></a></h2>
<p>This example demonstrates inconsistent behavior for the same
container performing the same operations at runtime. As the current
specification for block-based containers does not preserve elements,
very different results are produced when acting on the same set of
values held by a vector, depending only on non-value state of the vector
itself. This surprising behavior arises as
<code class="sourceCode default">vector</code> has different behavior
when inserting at capacity, compared to typical insertions that do not
require reallocation.</p>
<p>To emphasize we that we are acting on the same object with the same
set of values, the example uses lambda objects with reference captures
to guarantee that all the operations are happening in the same order on
the same elements.</p>
<p>First, we reserve up to a capacity of four, and check that the exact
requested capacity is respected. Then we iterate twice: on each pass, we
first clear the vector and fill it with four identical items; then we
insert a different item into the middle of the vector, at position two;
finally we log the state of the vector, writing the value of each
element, and then name of the variable each element is bound to.</p>
<p>Therefore the first run through the sequence of lambda operations
will relocate elements into a new buffer as the
<code class="sourceCode default">vector</code> must expand, while the
second run through the lambdas will operate purely within the existing
buffer.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cassert&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;tuple&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;vector&gt;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> a <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> b <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> element <span class="op">=</span> std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;</span>;</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>element<span class="op">&gt;</span> v;</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>    v<span class="op">.</span>reserve<span class="op">(</span><span class="dv">4</span><span class="op">)</span>;</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="dv">4</span> <span class="op">==</span> v<span class="op">.</span>capacity<span class="op">())</span>;</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> fill <span class="op">=</span> <span class="op">[&amp;](</span><span class="dt">int</span> <span class="op">&amp;</span> i <span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>        v<span class="op">.</span>clear<span class="op">()</span>;</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> j <span class="op">=</span> <span class="dv">0</span>; j <span class="op">!=</span> <span class="dv">4</span>; <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>            v<span class="op">.</span>emplace_back<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> inject <span class="op">=</span> <span class="op">[&amp;](</span><span class="dt">int</span> <span class="op">&amp;</span> i<span class="op">)</span> <span class="op">{</span> v<span class="op">.</span>emplace<span class="op">(</span>v<span class="op">.</span>begin<span class="op">()</span> <span class="op">+</span> <span class="dv">2</span>, i<span class="op">)</span>; <span class="op">}</span>;</span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> report <span class="op">=</span> <span class="op">[&amp;]</span> <span class="op">{</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> j <span class="op">:</span> v<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>j<span class="op">)</span>;</span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> j <span class="op">:</span> v<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a>           <span class="cf">if</span> <span class="op">(&amp;</span>a <span class="op">==</span> <span class="op">&amp;</span>std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>j<span class="op">))</span> <span class="op">{</span></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a>                std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;a&#39;</span>;</span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a>            <span class="cf">else</span> <span class="cf">if</span> <span class="op">(&amp;</span>b <span class="op">==</span> <span class="op">&amp;</span>std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>j<span class="op">))</span> <span class="op">{</span></span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a>                std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;b&#39;</span>;</span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a>            <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb3-37"><a href="#cb3-37" aria-hidden="true" tabindex="-1"></a>                std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;?&#39;</span>;</span>
<span id="cb3-38"><a href="#cb3-38" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb3-39"><a href="#cb3-39" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb3-40"><a href="#cb3-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-41"><a href="#cb3-41" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb3-42"><a href="#cb3-42" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-44"><a href="#cb3-44" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> dummy <span class="op">:</span> <span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">})</span> <span class="op">{</span></span>
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true" tabindex="-1"></a>        fill<span class="op">(</span>a<span class="op">)</span>;</span>
<span id="cb3-46"><a href="#cb3-46" aria-hidden="true" tabindex="-1"></a>        inject<span class="op">(</span>b<span class="op">)</span>;</span>
<span id="cb3-47"><a href="#cb3-47" aria-hidden="true" tabindex="-1"></a>        report<span class="op">()</span>;</span>
<span id="cb3-48"><a href="#cb3-48" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-49"><a href="#cb3-49" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>How well can you predict the answer without looking ahead<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>?</p>
<p>Did you predict the first iteration would report exactly one
reference to <code class="sourceCode default">b</code> in the middle of
the vector? Did you predict the second iteration would contain no
references to <code class="sourceCode default">b</code>? Did you predict
the final state would contain values that all appear equal to
<code class="sourceCode default">b</code>, as
<code class="sourceCode default">a</code> is overwritten by
<code class="sourceCode default">insert</code> on the second iteration
of the loop?</p>
<p>Take note again, that in both iterations the initial value of the
vector before the <code class="sourceCode default">emplace</code> in
<code class="sourceCode default">inject</code> is exactly four
references to <code class="sourceCode default">a</code>; the different
behaviors at runtime are entirely due to the
<code class="sourceCode default">vector</code> being at capacity for an
insertion, or not.</p>
<p>In practice, such issues are much harder to track down outside a test
program that has been specifically designed to demonstrate the problem.
How well do you think the typical non-committee developer would predict
this behavior without the warm-up of a paper describing the specific
concern? I will admit that as paper author, the part assigning
<code class="sourceCode default">a</code> to
<code class="sourceCode default">b</code> caught me out even as I was
writing this example for the paper!</p>
<h1 data-number="5" id="related-lwg-issues"><span class="header-section-number">5</span> Related LWG issues<a href="#related-lwg-issues" class="self-link"></a></h1>
<!-- TBD: TERSE ABSTRACT, NOT YET ENGLISH EXPLANATION -->
<ul>
<li>see also <span class="citation" data-cites="LWG3758">[<a href="#ref-LWG3758" role="doc-biblioref">LWG3758</a>]</span>, trying to
make the problem worse!</li>
<li>see also <span class="citation" data-cites="LWG2158">[<a href="#ref-LWG2158" role="doc-biblioref">LWG2158</a>]</span>.
Conditional copy/move in
<code class="sourceCode default">std::vector</code></li>
<li>see also <span class="citation" data-cites="LWG1102">[<a href="#ref-LWG1102" role="doc-biblioref">LWG1102</a>]</span>,
<code class="sourceCode default">std::vector</code>’s reallocation
policy still unclear</li>
<li>drive-by fix <span class="citation" data-cites="LWG3308">[<a href="#ref-LWG3308" role="doc-biblioref">LWG3308</a>]</span>, on
<code class="sourceCode default">erase</code> not invalidating iterators
unless elements actually erased</li>
</ul>
<!-- 
  This comment is directly copy/pasting text from the earlier P2786 that should
  be reflected in the content is _this_ document.  It is intended to be
  plundered for any useful wording or missed points, and then deleted.

# The Problem With Vector

The goal of our optimization, through trivial relocation, is to make moving
elements around a block container, such as `vector` or `deque`, more efficient.
Bloomberg's experience with their implementation of polymorphic memory
resources has demonstrated this value for many years.  However, as we prepared
this paper, Arthur O'dwyer pointed out that we are taking liberties that the
standard does not permit.  In particular, when erasing an element from the
middle of a `vector`, or inserting an element into the middle of a `vector`,
the existing elements are currently relocated using `operator=`, and if the
result of the assignment operator for an element is not exactly the same as
destroying the target element and then move constructing into it, then Bad
Things can happen.  We did not run into this problem at Bloomberg, as the
polymorphic memory resource model ensures that all elements in a container use
the same memory resource, and (as polymorphic allocators are equal) assignment
and move-construction will produce the same result.  However, we do not have an
easily testable property to confirm that runtime condition is guaranteed by a
`vector` itself --- we are relying on implementation knowledge.



### [container.reqmts] Containers                       {-}

```
typename X::value_type
```
[2]{.pnum}
_Result:_ `T`

[3]{.pnum}
_Preconditions:_ `T` is _Cpp17Erasable_ from `X`
(see [container.alloc.reqmts]{.ref}, below).


[66.3]{.pmum}
No `erase()`, `clear()`, `pop_back()` or `pop_front()` function throws an
exception.


### [sequence.reqmts]{.sref} Sequence containers        {-}

```
a.erase(q)
```
[45]{.pnum}
_Result:_ `iterator`.

[46]{.pnum}
_Preconditions:_ For `vector` and `deque`, `T` is _Cpp17MoveAssignable_.

[47]{.pnum}
_Effects:_ Erases the element pointed to by `q`.

[48]{.pnum}
_Returns:_ An iterator that points to the element immediately following `q`
prior to the element being erased. If no such element exists, `a.end()` is
returned.



To make the concern more visible, consider the following example where we store
`std::pmr::vector` elements in a `std::vector`, i.e, the outer `vector` is
using the default `std::allocator` that knows nothing about `pmr` memory
resources.  We will demonstrate, using a lambda, that running through the same
code can produce very different results on which elements use which memory
resource, depending on whether the `vector` reallocates to increase capacity.

```cpp
#include <cassert>
#include <memory_resource>
#include <utility>
#include <vector>

int main() {
   using Element = std::pmr::vector<int>;
   using Container = std::vector<Element>;

   Container v;
   v.reserve(4);
   assert(4 == v.capacity());     // confirm initial capacity for first run

   using Alloc = std::pmr::monotonic_buffer_resource;
   Alloc a0, a1, a2, a3, a4;      // create 5 distinct allocators to track

    // test case is a lambda to ensure both runs are executing the same source code.
   auto fill = [&](bool firstTime) {

      // create 5 elements, each using a different memory resource
      Element e0{ {1, 2, 3}, &a0};
      Element e1{ {2, 3, 4}, &a1};
      Element e2{ {3, 4, 5}, &a2};
      Element e3{ {4, 5, 6}, &a3};
      Element e4{ {5, 6, 7}, &a4};

      // move the first 4 elements into the container, retaining their resource
      v.emplace_back(std::move(e0));
      v.emplace_back(std::move(e1));
      v.emplace_back(std::move(e2));
      v.emplace_back(std::move(e3));

      // verify each element has retained its memory resource
      assert(&a0 == v[0].get_allocator().resource());
      assert(&a1 == v[1].get_allocator().resource());
      assert(&a2 == v[2].get_allocator().resource());
      assert(&a3 == v[3].get_allocator().resource());

      // emplace an element into the middle of the container
      v.emplace(v.begin() + 2, std::move(e4));

      // Verify the memory resource used by each element after insertion, which
      // is different on the first run where the vector must grow its capacity,
      // compared to any following runs where elements are moved without
      // reallocation.

      assert(&a0 == v[0].get_allocator().resource());
      assert(&a1 == v[1].get_allocator().resource());
      if (firstTime) {
         // for the first run, the vector expands and each element has the right resource
         assert(&a4 == v[2].get_allocator().resource());
         assert(&a2 == v[3].get_allocator().resource());
         assert(&a3 == v[4].get_allocator().resource());
      }
      else {
         // for later runs, the vector rotates elements giving different resources
         assert(&a2 == v[2].get_allocator().resource());
         assert(&a3 == v[3].get_allocator().resource());
         assert(&a3 == v[4].get_allocator().resource());
      }
   };

   fill(true);   // first run to fill the vector `v`

   v.clear();    // reset the vector for a second run without losing capacity

   fill(false);  // next run to fill the vector `v`
}
```

The topic of relocation within _block-based containers_ such as `std::vector`
is the topic of paper [@P2959R0], which addresses concerns beyond just the
trivial relocation optimization.

  -->
<h1 data-number="6" id="current-specification"><span class="header-section-number">6</span> Current Specification<a href="#current-specification" class="self-link"></a></h1>
<p>To understand the concerns we will raise, we should first ensure we
understand exactly what the standard specifies.</p>
<h2 data-number="6.1" id="elements-are-created-using-allocator_traitsconstruct"><span class="header-section-number">6.1</span> Elements are created using
<code class="sourceCode default">allocator_traits::construct</code><a href="#elements-are-created-using-allocator_traitsconstruct" class="self-link"></a></h2>
<!-- TBD: TERSE ABSTRACT, NOT YET ENGLISH EXPLANATION -->
<p>Internal relocation, e.g., to a new
<code class="sourceCode default">vector</code> buffer, must use
<code class="sourceCode default">allocator_traits::construct</code>
which can select a potentially-throwing form, i.e.,
<code class="sourceCode default">noexcept(false)</code>, rather than the
typically non-throwing move constructor.</p>
<p>Designed to work with <code class="sourceCode default">pmr</code>
data structures that assume all allocators are the same, as managed by
the <code class="sourceCode default">construct</code> calls — but must
go through run-time test for allocators every time, as
<code class="sourceCode default">allocator_traits</code>, through the
assignment operators that we must delegate to, cannot make that
assumption.</p>
<p>A vendor hand-code a partial specialization of
<code class="sourceCode default">pmr</code> containers to apply the
internal knowledge, much like Bloomberg BDE, but that defeats the point
of a primary template that is allocator-aware and should just Do The
Right Thing, rather than defer to vendor QoI and difficult proof of
<em>as-if</em> rules taking advantage of assumptions of
allocator-equality. Note that if we cannot prove the <em>as-if</em>
constraint to our satisfaction, then such an optimization is also
non-conforming.</p>
<h2 data-number="6.2" id="elements-are-replaced-using-move-assignment"><span class="header-section-number">6.2</span> Elements are replaced using
move-assignment<a href="#elements-are-replaced-using-move-assignment" class="self-link"></a></h2>
<!-- TBD NEEDS MORE DETAIL -->
<p>When a block-container moves elements to restore contiguity after an
<code class="sourceCode default">erase</code>, or when moving elements
within existing capacity to support an
<code class="sourceCode default">insert</code>, the container
requirements specify that existing elements are replaced through move
assignment, rather than through destruction followed by move
construction.</p>
<p>Node-based containers simply rearrange their nodes without touching
any existing elements.</p>
<p>As we shall see below, there are a set of types where this
inconsistency for internal rearrangement of elements has an observable
difference of behavior that is not only surprising, but often
counterproductive in those cases.</p>
<h1 data-number="7" id="concerns"><span class="header-section-number">7</span> Concerns<a href="#concerns" class="self-link"></a></h1>
<p>There are several concerns raised by the current library
specification, that become magnified once we consider applying trivial
relocation optimizations. The concerns arise from two distinct sources:
1) from a container’s element type, and 2) from a container’s allocator
type.</p>
<h2 data-number="7.1" id="replacing-elements-by-move-assignment-rather-than-move-construction"><span class="header-section-number">7.1</span> Replacing elements by
move-assignment rather than move-construction<a href="#replacing-elements-by-move-assignment-rather-than-move-construction" class="self-link"></a></h2>
<p>When move-assignment for an element type produces a different state
to destruction followed by move-construction, block containers behave
very differently to node-based containers, that merely move the nodes
rather than the elements. This behavior is very clearly specified, not
undefined behavior or some other failure on the users’ part to supply a
good type; the end result is predictable from the inputs in every case,
even if it may be surprising.</p>
<p>For example, consider the two <a href="#eg.listvlist">motivating</a>
<a href="#eg.vectorvvector">examples</a> at the start of this document,
which use nothing but standard types.</p>
<p>For another example, if we erase an element from the middle of a
container, <code class="sourceCode default">std::vector&lt;std::pmr::string&gt;&gt;</code>
behaves very differently to <code class="sourceCode default">std::list&lt;std::pmr::string&gt;&gt;</code>;
the <code class="sourceCode default">list</code> moves nodes to relocate
elements, preserving allocators <em>and</em> values of the stored
strings, while the <code class="sourceCode default">vector</code> moves
<em>values</em>, resulting in reallocation, and the moved values landing
in different <em>elements</em>.</p>
<p>We would like <code class="sourceCode default">vector</code> to
behave more like <code class="sourceCode default">list</code> for all of
these examples.</p>
<!--
  E.g., code example erasing from middle of a container, and showing how
  allocators do, or do not, follow their elements.  Note /internal/ relocation
  of elements vs external manipulation of values.

  This would be a copy of the initial list vs vector example, but using `pmr`
  allocators and a custom memory resource that tracks allocate and deallocate
  calls.
  -->
<h2 data-number="7.2" id="allocators-may-care-about-element-identity"><span class="header-section-number">7.2</span> Allocators may care about
element identity<a href="#allocators-may-care-about-element-identity" class="self-link"></a></h2>
<p>If an allocator customizes the
<code class="sourceCode default">conatruct</code> function, it should
also customize the <code class="sourceCode default">destroy</code>
function. Internal relocation by assignment might then violate allocator
expectations for <code class="sourceCode default">destroy</code>,
especially if the identity (i.e., the address) of the constructed
elements matters.</p>
<p>For brevity, we will defer a simple example of this to the case of
supporting trivial relocation (per <span class="citation" data-cites="P2786R2">[<a href="#ref-P2786R2" role="doc-biblioref">P2786R2</a>]</span>. In practice, containers will
traffic in the correct sequence of paired
<code class="sourceCode default">construct</code> and
<code class="sourceCode default">destruct</code> calls for objects
created at those addresses if use a simple example such as telemetry to
match <code class="sourceCode default">construct</code> calls to
<code class="sourceCode default">destroy</code> calls — to properly
demonstrate a dependence on object identity we need a stronger coupling
between the object and the allocator, such as logging specific
operations. However, attempts to provide an example that was compelling
rather than artificial proved tricky</p>
<p>For reference, this is the kind of allocator we are thinking about
that becomes compelling only in the presence of trivial optimizations.
Note that this example assumes C++20<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Element<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Telemark <span class="op">:</span> std<span class="op">::</span>allocator<span class="op">&lt;</span>Element<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>   std<span class="op">::</span>set<span class="op">&lt;</span><span class="dt">void</span> <span class="op">*&gt;</span> <span class="op">&amp;</span> d_owned;</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>   <span class="kw">using</span> alloctor<span class="op">::</span>allocator;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>   Telemark<span class="op">(</span>std<span class="op">::</span>set<span class="op">&lt;</span><span class="dt">void</span> <span class="op">*&gt;</span> <span class="op">&amp;</span>telemetry<span class="op">)</span> <span class="op">:</span> d_owned<span class="op">{</span>telemetry<span class="op">}</span> <span class="op">{}</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>   <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>   <span class="dt">void</span> construct<span class="op">(</span>T<span class="op">*</span> p, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(!</span>d_owned<span class="op">.</span>emplace<span class="op">(</span>p<span class="op">).</span>second<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>         std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Overwrite at &quot;</span> <span class="op">&lt;&lt;</span> <span class="op">(</span><span class="dt">void</span> <span class="op">*)</span>p <span class="op">&lt;&lt;</span> std<span class="op">::</span>endl;</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>      <span class="op">::</span><span class="kw">new</span><span class="op">((</span><span class="dt">void</span><span class="op">*)</span>p<span class="op">)</span> T<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Args<span class="op">...&gt;(</span>args<span class="op">...))</span>;</span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>   <span class="op">}</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>   <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>   <span class="dt">void</span> destroy<span class="op">(</span>T<span class="op">*</span> p<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(!</span>d_owned<span class="op">.</span>erase<span class="op">(</span>p<span class="op">))</span> <span class="op">{</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>         std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Bad destroy at &quot;</span> <span class="op">&lt;&lt;</span> <span class="op">(</span><span class="dt">void</span> <span class="op">*)</span>p <span class="op">&lt;&lt;</span> std<span class="op">::</span>endl;</span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a>   <span class="op">}</span></span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<h2 data-number="7.3" id="strong-exception-safety-guarantee-may-be-broken"><span class="header-section-number">7.3</span> Strong exception safety
guarantee may be broken<a href="#strong-exception-safety-guarantee-may-be-broken" class="self-link"></a></h2>
<p>One of the cornerstones of the C++ Standard Library contracts is the
notion of the basic and the strong exception safety guarantees (although
they are never called that in the standard). The basic guarantee simply
promises no resource leaks and retains object invariants if an exception
is thrown by a function, whereas the strong exception safety guarantee
strengthens the basic by additionally promising that if an exception
propagates from a function, then no side effects will occur.</p>
<p>Several containers offer the strong exception safety guarantee when
inserting at the end of that container, including
<code class="sourceCode default">std::vector</code>. In the case of
<code class="sourceCode default">vector</code> the only circumstances
under which the strong exception safety guarantee is reduced to the
basic are: * the element type does not have a
<code class="sourceCode default">noexcept</code> move constructor, and *
the element type is not copy constructible</p>
<p>There is no leeway given for the
<code class="sourceCode default">allocator_traits::construct</code>
function itself throwing, so the following program should be a simple
demonstration of the strong exception safety guarantee when the
allocator throws on its 8th construction.</p>
<p>In practice, a library can observe that the default implementation of
<code class="sourceCode default">allocator_traits::construct</code>
simply calls placement new, and can throw only if the called constructor
can throw — so optimizing by directly calling the move constructor is a
correct implementation for as-if behavior so long the container’s
allocator does not provide a
<code class="sourceCode default">construct</code> call;
<code class="sourceCode default">std::allocator</code> relies on the
default
<code class="sourceCode default">allocator_traits::construct</code>
implementation. Once control is transferred to the allocator function
though, the assumption no longer holds, even if the
<code class="sourceCode default">construct</code> call is marked
<code class="sourceCode default">noexcept</code>; the allocator may want
to store additional information such as the address of constructed
elements, which would be lost if the move constructor is called
directly. A <code class="sourceCode default">noexcept</code>
<code class="sourceCode default">allocator::construct</code> would still
allow an implementation to avoid the cost of making a redundant copy to
roll back.</p>
<p>Note that correcting the current implementations to honor the strong
exception safety guarantee in this case could be an extreme
pessimization for allocators that are not
<code class="sourceCode default">std::allocator</code>. For example,
<code class="sourceCode default">std::pmr::vector&lt;std::pmr::string&gt;&gt;</code>
would be required to copy its strings on a vector reallocation rather
than simply moving them as today, unless the library vendor provides a
partial specialization for <code class="sourceCode default">std::vector&lt;T, std::pmr::polymorphic_allocator&lt;T&gt;&gt;</code>
to exploit the knowledge that moving
<code class="sourceCode default">pmr</code> elements is safe due to
semantic guarantees provided by the contract of
<code class="sourceCode default">pmr::polymorphic_allocator</code> and
enforced by the <code class="sourceCode default">constuct</code>
calls.</p>
<p>This paper will propose a more general solution than partially
specializing containers for each allocator that wants to preserve my
move construction optimization.</p>
<h3 data-number="7.3.1" id="example-current-vector-implementations-break-for-custom-allocators"><span class="header-section-number">7.3.1</span> Example: Current
<code class="sourceCode default">vector</code> implementations break for
custom allocators<a href="#example-current-vector-implementations-break-for-custom-allocators" class="self-link"></a></h3>
<p>As a quick guide to the minimal example: * This examples assumes
C++20<a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a> *
<code class="sourceCode default">MyAlloc</code> is an allocator that
derives from <code class="sourceCode default">std::allocator</code> to
fulfil all basic allocator requirements, while providing its own
<code class="sourceCode default">construct</code> call *
<code class="sourceCode default">sharedptr&lt;int&gt;</code> is a
standard library class with both a non-throwing move constructor and a
copy constructor * The <code class="sourceCode default">report</code>
lambda object simply displays the contents of the
<code class="sourceCode default">vector</code> to ensure that the strong
exception safety guatrantee is honored</p>
<!--
This program shows that rather than using the allocator `construct` call,
current standard library implementations will directly move elements when the
`vector` element type has a noexcept move constructor.  When an
`allocator::construct` call throws, rather than the move constructor, all known
implementations of `std::vector` leave the original object in a state that
honors the basic guarantee, but not the strong exception safety guarantee.
  -->
<p>The allocator supplied to the container is designed to throw after
constructing a specific number of elements. The program is set up to
ensure that number corresponds to creating one of the middle elements in
a new vector buffer when an insertion at the back of the vector must
reallocate.</p>
<p>The point being made is that
<code class="sourceCode default">shared_ptr</code> satisfies the library
requirements to demand the strong exception safety guarantee, but
implementations simply look at the
<code class="sourceCode default">shared_ptr</code> interface itself to
conclude that they can safely move elements without creating a back-up,
a la copy/swap idiom, despite the allocator’s
<code class="sourceCode default">construct</code> call causing the
problem.</p>
<p>As long as an allocator does not supply its own
<code class="sourceCode default">construct</code> call, the as-if
interpretation means that vendors understand that a vector does not need
to additionally protect itself against the concerns of a bad
<code class="sourceCode default">construct</code>, and the straight
<code class="sourceCode default">move</code> optimization is valid.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>#include &lt;iostream&gt;</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>#include &lt;memory&gt;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>#include &lt;vector&gt;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>#include &lt;utility&gt;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>template &lt;class ELEM&gt;</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>struct MyAlloc : std::allocator&lt;ELEM&gt; {</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>    inline static int count = 0;</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    using std::allocator&lt;ELEM&gt;::allocator;</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>    template&lt;class T, class... Args&gt;</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>    void construct(T* p, Args&amp;&amp;... args) {</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>        if(8 == ++count) { throw count; }</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a>        //std::cout &lt;&lt; count &lt;&lt; &quot;\n&quot;;</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>        ::new(p) T(std::forward&lt;Args...&gt;(args...));</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a>int main(int argc, const char * argv[]) {</span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a>    using namespace std;</span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a>    vector&lt;shared_ptr&lt;int&gt;, MyAlloc&lt;shared_ptr&lt;int&gt;&gt;&gt; v;</span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a>    v.reserve(4);</span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a>    auto report = [&amp;] {</span>
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a>        cout &lt;&lt; &quot;Report:\n&quot;;</span>
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a>        for (auto &amp;elem : v) {</span>
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a>            cout &lt;&lt; &quot;\t&quot; &lt;&lt; elem &lt;&lt; &quot;\n&quot;;</span>
<span id="cb6-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a>        }</span>
<span id="cb6-33"><a href="#cb6-33" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb6-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a>    cout &lt;&lt; &quot;Fill:\n&quot;;</span>
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a>    for (int i = 0; i != 4; ++i) {</span>
<span id="cb6-38"><a href="#cb6-38" aria-hidden="true" tabindex="-1"></a>        v.emplace_back(make_shared&lt;int&gt;(i));</span>
<span id="cb6-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb6-40"><a href="#cb6-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-41"><a href="#cb6-41" aria-hidden="true" tabindex="-1"></a>    report();</span>
<span id="cb6-42"><a href="#cb6-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-43"><a href="#cb6-43" aria-hidden="true" tabindex="-1"></a>    cout &lt;&lt; &quot;Grow:\n&quot;;</span>
<span id="cb6-44"><a href="#cb6-44" aria-hidden="true" tabindex="-1"></a>    try {</span>
<span id="cb6-45"><a href="#cb6-45" aria-hidden="true" tabindex="-1"></a>        v.emplace_back(make_shared&lt;int&gt;(4));</span>
<span id="cb6-46"><a href="#cb6-46" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb6-47"><a href="#cb6-47" aria-hidden="true" tabindex="-1"></a>    catch(int) {</span>
<span id="cb6-48"><a href="#cb6-48" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb6-49"><a href="#cb6-49" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-50"><a href="#cb6-50" aria-hidden="true" tabindex="-1"></a>    report();</span>
<span id="cb6-51"><a href="#cb6-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-52"><a href="#cb6-52" aria-hidden="true" tabindex="-1"></a>    cout &lt;&lt; &quot;Done:\n&quot;;</span>
<span id="cb6-53"><a href="#cb6-53" aria-hidden="true" tabindex="-1"></a>    return 0;</span>
<span id="cb6-54"><a href="#cb6-54" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>In practice, all known standard library implementations fail this
test, including the Bloomberg BDE library, as they call the move
constructor directly. Indeed, the library guarantees are written with
respect to the move constructor, rather than the allocator call, almost
as is this were the intended behavior.</p>
<p>Typical output from running the test example above:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>Fill:</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>Report:</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    0x559e8d8db318</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    0x559e8d8db348</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>    0x559e8d8db378</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    0x559e8d8db3a8</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>Grow:</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>Report:</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>    0x559e8d8db318</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>    0x559e8d8db348</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>    (nil)</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>    (nil)</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>Done:</span></code></pre></div>
<p>Different implementations might move the elements in a different
order, so the position of the empty shared pointers violating the strong
exception safety guarantee will vary by Standard Library
implementation.</p>
<h2 data-number="7.4" id="supporting-trivial-optimizations"><span class="header-section-number">7.4</span> Supporting trivial
optimizations<a href="#supporting-trivial-optimizations" class="self-link"></a></h2>
<p>The intent of paper <span class="citation" data-cites="P2786R2">[<a href="#ref-P2786R2" role="doc-biblioref">P2786R2</a>]</span> is to
introduce into the Core language specification a new category of type
that can be exploited to optimize relocation within data structures,
including those in the C++ Standard Library. However, the preceding
concerns also inhibit exploiting knowledge of trivial relocatability if
a container’s allocator supplies an implementation of
<code class="sourceCode default">construct</code>. The following example
demonstrates a simple failure case if trivial relocation is exploited,
as the allocator cares about the address of the elements it constructs
and destroys, but is not informed if the elements are moved into the new
vector buffer by merely copying the bytes.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cassert&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;memory&gt;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;set&gt;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;vector&gt;</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Element<span class="op">&gt;</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Telemark <span class="op">:</span> std<span class="op">::</span>allocator<span class="op">&lt;</span>Element<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>   std<span class="op">::</span>set<span class="op">&lt;</span><span class="dt">void</span> <span class="op">*&gt;</span> <span class="op">&amp;</span> d_owned;</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>   <span class="kw">using</span> alloctor<span class="op">::</span>allocator;</span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>   Telemark<span class="op">(</span>std<span class="op">::</span>set<span class="op">&lt;</span><span class="dt">void</span> <span class="op">*&gt;</span> <span class="op">&amp;</span>telemetry<span class="op">)</span> <span class="op">:</span> d_owned<span class="op">{</span>telemetry<span class="op">}</span> <span class="op">{}</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>   <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a>   <span class="dt">void</span> construct<span class="op">(</span>T<span class="op">*</span> p, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(!</span>d_owned<span class="op">.</span>emplace<span class="op">(</span>p<span class="op">).</span>second<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a>         std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Overwrite at &quot;</span> <span class="op">&lt;&lt;</span> <span class="op">(</span><span class="dt">void</span> <span class="op">*)</span>p <span class="op">&lt;&lt;</span> std<span class="op">::</span>endl;</span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a>      <span class="op">::</span><span class="kw">new</span><span class="op">((</span><span class="dt">void</span><span class="op">*)</span>p<span class="op">)</span> T<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Args<span class="op">...&gt;(</span>args<span class="op">...))</span>;</span>
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a>   <span class="op">}</span></span>
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a>   <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb8-27"><a href="#cb8-27" aria-hidden="true" tabindex="-1"></a>   <span class="dt">void</span> destroy<span class="op">(</span>T<span class="op">*</span> p<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-28"><a href="#cb8-28" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(!</span>d_owned<span class="op">.</span>erase<span class="op">(</span>p<span class="op">))</span> <span class="op">{</span></span>
<span id="cb8-29"><a href="#cb8-29" aria-hidden="true" tabindex="-1"></a>         std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Bad destroy at &quot;</span> <span class="op">&lt;&lt;</span> <span class="op">(</span><span class="dt">void</span> <span class="op">*)</span>p <span class="op">&lt;&lt;</span> std<span class="op">::</span>endl;</span>
<span id="cb8-30"><a href="#cb8-30" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb8-31"><a href="#cb8-31" aria-hidden="true" tabindex="-1"></a>   <span class="op">}</span></span>
<span id="cb8-32"><a href="#cb8-32" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb8-33"><a href="#cb8-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-34"><a href="#cb8-34" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-35"><a href="#cb8-35" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> a <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb8-36"><a href="#cb8-36" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> b <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb8-37"><a href="#cb8-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-38"><a href="#cb8-38" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>set<span class="op">&lt;</span><span class="dt">void</span> <span class="op">*&gt;</span> registry;</span>
<span id="cb8-39"><a href="#cb8-39" aria-hidden="true" tabindex="-1"></a>    Telemark<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> alloc<span class="op">{</span>registry<span class="op">}</span>;</span>
<span id="cb8-40"><a href="#cb8-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-41"><a href="#cb8-41" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span>, Telemark<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;</span> v<span class="op">{</span>alloc<span class="op">}</span>;</span>
<span id="cb8-42"><a href="#cb8-42" aria-hidden="true" tabindex="-1"></a>    v<span class="op">.</span>reserve<span class="op">(</span><span class="dv">4</span><span class="op">)</span>;</span>
<span id="cb8-43"><a href="#cb8-43" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="dv">4</span> <span class="op">==</span> v<span class="op">.</span>capacity<span class="op">())</span>;</span>
<span id="cb8-44"><a href="#cb8-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-45"><a href="#cb8-45" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> fill <span class="op">=</span> <span class="op">[&amp;](</span><span class="dt">int</span> <span class="op">&amp;</span> i <span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-46"><a href="#cb8-46" aria-hidden="true" tabindex="-1"></a>        v<span class="op">.</span>clear<span class="op">()</span>;</span>
<span id="cb8-47"><a href="#cb8-47" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> j <span class="op">=</span> <span class="dv">0</span>; j <span class="op">!=</span> <span class="dv">4</span>; <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-48"><a href="#cb8-48" aria-hidden="true" tabindex="-1"></a>            v<span class="op">.</span>emplace_back<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb8-49"><a href="#cb8-49" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb8-50"><a href="#cb8-50" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb8-51"><a href="#cb8-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-52"><a href="#cb8-52" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> inject <span class="op">=</span> <span class="op">[&amp;](</span><span class="dt">int</span> <span class="op">&amp;</span> i<span class="op">)</span> <span class="op">{</span> v<span class="op">.</span>emplace<span class="op">(</span>v<span class="op">.</span>begin<span class="op">()</span> <span class="op">+</span> <span class="dv">2</span>, i<span class="op">)</span>; <span class="op">}</span>;</span>
<span id="cb8-53"><a href="#cb8-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-54"><a href="#cb8-54" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> report <span class="op">=</span> <span class="op">[&amp;]</span> <span class="op">{</span></span>
<span id="cb8-55"><a href="#cb8-55" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> j <span class="op">:</span> v<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-56"><a href="#cb8-56" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> j;</span>
<span id="cb8-57"><a href="#cb8-57" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb8-58"><a href="#cb8-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-59"><a href="#cb8-59" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb8-60"><a href="#cb8-60" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb8-61"><a href="#cb8-61" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-62"><a href="#cb8-62" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> dummy <span class="op">:</span> <span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">})</span> <span class="op">{</span></span>
<span id="cb8-63"><a href="#cb8-63" aria-hidden="true" tabindex="-1"></a>        fill<span class="op">(</span>a<span class="op">)</span>;</span>
<span id="cb8-64"><a href="#cb8-64" aria-hidden="true" tabindex="-1"></a>        inject<span class="op">(</span>b<span class="op">)</span>;</span>
<span id="cb8-65"><a href="#cb8-65" aria-hidden="true" tabindex="-1"></a>        report<span class="op">()</span>;</span>
<span id="cb8-66"><a href="#cb8-66" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb8-67"><a href="#cb8-67" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<!-- AJM moved to the introduction
## _Element_ behavior is not a concern for algorithms

Algorithms work with values, not elements, so are not concerned with
constructing and destroying objects, simply moving around values in objects
that they reference but do not own
  -->
<h2 data-number="7.5" id="relocation-creates-objects-just-like-the-uninitialized-standard-algorithms"><span class="header-section-number">7.5</span> Relocation creates objects just
like the <code class="sourceCode default">uninitialized</code> standard
algorithms<a href="#relocation-creates-objects-just-like-the-uninitialized-standard-algorithms" class="self-link"></a></h2>
<p>While most algorithms do not care about constructing new objects, the
<code class="sourceCode default">uninitialized_*</code> algorithms in
the <code class="sourceCode default">&lt;memory&gt;</code> header are
the counter-example. For consistency, the trivial relocation support
added by <span class="citation" data-cites="P2786R2">[<a href="#ref-P2786R2" role="doc-biblioref">P2786R2</a>]</span> should be
extended to support the object creation function templates in the
Standard Library.</p>
<p>// vvvTHISvvv SHOULD BE REPHRASED AS AN EASE-OF-USE CONCERN</p>
<p>Similarly, for ease of use, a general purpose
<code class="sourceCode default">relocate</code> function that uses move
construction, and safely adopts trivial relocation optimizations where
available, should be added to
<code class="sourceCode default">&lt;memory&gt;</code> header.</p>
<h1 data-number="8" id="proposed-changes"><span class="header-section-number">8</span> Proposed Changes<a href="#proposed-changes" class="self-link"></a></h1>
<p>We propose adding a new type trait as a user customization point to
indicate types that have inconsistent construction/assignment behavior.
This can be used as a hint where code is concerned with the difference.
The minimal set of library components is then updated to forward this
trait when needed.</p>
<p>We further propose adding a non-static member function to
<code class="sourceCode default">allocator_traits</code> to support
internal relocation/replacement that defaults to the current behavior
when an allocator does not supply its own implementation, and the hint
trait above produces
<code class="sourceCode default">false_type</code>.</p>
<h2 data-number="8.1" id="new-type-trait-container_replace_with_assignment"><span class="header-section-number">8.1</span> New type trait: <code class="sourceCode default">container_replace_with_assignment</code><a href="#new-type-trait-container_replace_with_assignment" class="self-link"></a></h2>
<p>To properly address <code class="sourceCode default">std::vector&lt;std::tuple&lt;T &amp;&gt;&gt;</code>
we need a new trait to establish that a type has a different outcome for
move-assignment than destroy/move-construction. To preserve backwards
compatibility, we must assume this property defaults to supporting
move-assignment, unless explicitly known to be
<code class="sourceCode default">false</code> by a (partial)
specialization of the new trait.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> container_replace_with_assignment <span class="op">:</span> is_move_assignable<span class="op">&lt;</span>T<span class="op">&gt;::</span>type <span class="op">{}</span>;</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> container_replace_with_assignment_v <span class="op">=</span> container_replace_with_assignment<span class="op">{}</span>;</span></code></pre></div>
<!--
  Needs a significant rephrasing --- this property is a non-breaking change
  as there are no types that will satisfy this specialization today, until the
  new facility ships and user types can start to opt in, electing for the
  changed behavior.
  -->
<p>Similarly, this property does not hold for many compound types
holding a member that does not have the assignment-is-construction
property (such as a reference), e.g.,
<code class="sourceCode default">tuple</code>,
<code class="sourceCode default">pair</code>, or
<code class="sourceCode default">array</code>. Maybe
<code class="sourceCode default">optional</code> and
<code class="sourceCode default">variant</code>?</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> <span class="op">...</span>TYPES<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> container_replace_with_assignment<span class="op">&lt;</span>tuple<span class="op">&lt;</span>TYPES<span class="op">...&gt;&gt;</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>   <span class="op">:</span> conjunction<span class="op">&lt;</span>container_replace_with_assignment<span class="op">&lt;</span>tuple<span class="op">&lt;</span>TYPES<span class="op">&gt;&gt;...&gt;::</span>type</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">{}</span>;</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="co">// also `pair`, `array`, funky views with reference semantics?</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="co">// --- play around with <em>movable-box</em> via `single_view`</span></span></code></pre></div>
<h2 data-number="8.2" id="new-non-static-member-function-allocator_traitsrelocate"><span class="header-section-number">8.2</span> New non-static member function:
<code class="sourceCode default">allocator_traits::relocate</code><a href="#new-non-static-member-function-allocator_traitsrelocate" class="self-link"></a></h2>
<!-- TBD: TERSE ASTRACT, NOT YET ENGLISH EXPLANATION -->
<p>If no <code class="sourceCode default">relocate</code> function is
supplied by the allocator, the implicit definition for
<code class="sourceCode default">allocator_traits::relocate</code>
is:</p>
<ul>
<li>if <code class="sourceCode default">allocator_type</code> defines
<code class="sourceCode default">relocate</code> member — call
<code class="sourceCode default">allocator_type::relocate</code></li>
<li>otherwise if allocator_type defines at least one of
<code class="sourceCode default">construct</code> and
<code class="sourceCode default">destroy</code> — use
<code class="sourceCode default">destroy</code>/<code class="sourceCode default">construct</code>-with-rvalue</li>
<li>otherwise if the element type is trivially copyable — use
<code class="sourceCode default">memmove</code>,
(<code class="sourceCode default">trivial_relocate</code> once <span class="citation" data-cites="P2786R2">[<a href="#ref-P2786R2" role="doc-biblioref">P2786R2</a>]</span> lands)</li>
<li>otherwise use move-assignment</li>
</ul>
<p>This formula officially supports optimization for trivially copyable
types (not going through
<code class="sourceCode default">construct</code>). Otherwise, this
revised definition has no change of behavior for
<code class="sourceCode default">std::allocator</code>, which reaches
last bullet.</p>
<ul>
<li><code class="sourceCode default">std</code> container of
<code class="sourceCode default">pmr</code> will work properly (semantic
change) only with trivial relocation, <span class="citation" data-cites="P2786R2">[<a href="#ref-P2786R2" role="doc-biblioref">P2786R2</a>]</span>, otherwise still old behavior
from <code class="sourceCode default">std::allocator</code></li>
<li><code class="sourceCode default">pmr</code> containers of
<code class="sourceCode default">pmr</code> will get
<code class="sourceCode default">pmr</code> optimization via new member,
<code class="sourceCode default">polymorphic_allocator::relocate</code></li>
</ul>
<h2 data-number="8.3" id="preferred-formula-for-allocator_traitsrelocate"><span class="header-section-number">8.3</span> Preferred formula for
<code class="sourceCode default">allocator_traits::relocate</code><a href="#preferred-formula-for-allocator_traitsrelocate" class="self-link"></a></h2>
<p>Finally, we reach our preferred formula for
<code class="sourceCode default">allocator_traits::relocate</code></p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">requires</span> <span class="kw">requires</span><span class="op">{</span> allocator<span class="op">::</span>relocate<span class="op">(...)</span>; <span class="op">})</span> <span class="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">// forward to allocator::relocate</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span><span class="op">(</span><span class="kw">requires</span> <span class="kw">requires</span><span class="op">{</span> allocator<span class="op">::</span>construct<span class="op">(...)</span>; <span class="op">})</span> <span class="op">{</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">// `allocator_traits::destroy(); allocator_traits::construct(rvalue)` each element</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>is_trivially_relocatable_v<span class="op">&lt;</span>T<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">// trivially relocate</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>container_replace_with_assignment_v<span class="op">&lt;</span>T<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// move-assign elements</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span> <span class="op">{</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>    <span class="co">// destroy-move-construct elements</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Note that in this formulation, the presence of
<code class="sourceCode default">construct</code> and
<code class="sourceCode default">destroy</code> trumps the element type
itself being trivially relocatable. In such cases, we defer that
optimization to the allocator itself providing a
<code class="sourceCode default">relocate</code> member.</p>
<h2 data-number="8.4" id="new-cpp17requirements-for-internal-relocation-in-a-block-container"><span class="header-section-number">8.4</span> New <em>Cpp17Requirements</em>
for internal relocation in a block container<a href="#new-cpp17requirements-for-internal-relocation-in-a-block-container" class="self-link"></a></h2>
<p>…</p>
<h2 data-number="8.5" id="worked-example"><span class="header-section-number">8.5</span> Worked example<a href="#worked-example" class="self-link"></a></h2>
<!-- TBD: TERSE ASTRACT, NOT YET ENGLISH EXPLANATION -->
<p>So let’s apply this formula to <code class="sourceCode default">std::vector&lt;std::pmr::vector&lt;T&gt;&gt;</code>:</p>
<ul>
<li><code class="sourceCode default">std::allocator</code> does not
provide a <code class="sourceCode default">relocate</code> member</li>
<li><code class="sourceCode default">std::allocator</code> does not
customize <code class="sourceCode default">construct</code> or
<code class="sourceCode default">destroy</code></li>
<li>the element type
<code class="sourceCode default">std::pmr::vector&lt;T&gt;</code> will
be trivially relocatable in the future, but let’s assume not for now to
observe the default semantics</li>
<li><code class="sourceCode default">container_replace_with_assignment_v&lt;std::pmr::vector&lt;T&gt;&gt;</code>
is <code class="sourceCode default">false</code>, as the vector has an
<code class="sourceCode default">allocator_type</code> that does not
propagate on move-assignment</li>
<li>destroy-then-move each
<code class="sourceCode default">std::pmr::vector&lt;T&gt;</code> to
perform relocation</li>
</ul>
<p>If we have a <code class="sourceCode default">pmr::vector&lt;pmr::vector&lt;T&gt;&gt;</code>,
then we should pick up a new
<code class="sourceCode default">relocate</code> member added to
<code class="sourceCode default">std::pmr::polymorphic_allocator</code>
as the first bullet, and that member will test and apply the trivial
relocation optimization if <code class="sourceCode default">T</code> is
trivially relocatable, or else fall back to construct/destroy:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> std<span class="op">::</span>pmr<span class="op">::</span>polymorphic_allocator<span class="op">::</span>relocate<span class="op">(...)</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>   <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>is_trivially_relocatable_v<span class="op">&lt;</span>T<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>      <span class="co">// trivially relocate</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>   <span class="op">}</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>   <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>container_replace_with_assignment_v<span class="op">&lt;</span>T<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>      <span class="co">// move-assign elements</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>   <span class="op">}</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>   <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>      <span class="co">// `allocator_traits::destroy(); allocator_traits::construct(rvalue)` each element</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>   <span class="op">}</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="9" id="optional-breaking-changes"><span class="header-section-number">9</span> Optional Breaking Changes<a href="#optional-breaking-changes" class="self-link"></a></h1>
<p>In addition to the basic proposal above, we strongly believe that a
small number of targeted fixes are important, even at the risk of
changing the runtime behavior of valid C++11 programs. However, without
these breaking changes the basic proposal remains an important
non-breaking change that enables trivial relocation optimizations, and
allows users to opt-in to containers correctly supporting their own
types’ semantics.</p>
<h2 data-number="9.1" id="fixing-vectortupleint"><span class="header-section-number">9.1</span> Fixing <code class="sourceCode default">vector&lt;tuple&lt;int&amp;&gt;&gt;</code><a href="#fixing-vectortupleint" class="self-link"></a></h2>
<p>Returning to our <a href="#eg.motivation">motivating examples</a> at
the top of this paper, the behavior of a
<code class="sourceCode default">tuple</code> containing a reference
element is not changed by the basic proposal and will continue with the
counter-intuitive behavior. The fix is to specialize <code class="sourceCode default">container_replace_with_assignment&lt;<em>reference-type</em>&gt;</code>
as <code class="sourceCode default">false_type</code>.</p>
<p>By default, the assignment-is-construction property does not hold for
reference types, even though the
<code class="sourceCode default">is_move_assignable_v</code> trait is
<code class="sourceCode default">true</code> for reference types. For
example, a simple aggregate struct holding a single reference member is
not move assignable either, and this is the behavior we expect from
tuples as container <em>elements</em>.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> container_replace_with_assignment <span class="op">:</span> bool_constant<span class="op">&lt;!</span>is_reference_v<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span> <span class="op">{}</span>;</span></code></pre></div>
<p>The issue is specific to
<code class="sourceCode default">tuple</code>,
<code class="sourceCode default">pair</code>,
<code class="sourceCode default">array</code>, etc. holding a member
reference, and would be addressed by changing the default for <code class="sourceCode default">container_replace_with_assignment&lt;<em>reference-type</em>&gt;</code></p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> container_replace_with_assignment <span class="op">:</span> is_move_assignable<span class="op">&lt;</span>T<span class="op">&gt;::</span>type <span class="op">{}</span>;</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> container_replace_with_assignment_v <span class="op">=</span> container_replace_with_assignment<span class="op">{}</span>;</span></code></pre></div>
<p>// should be not-a-reference-type</p>
<h2 data-number="9.2" id="fixing-element-types-using-allocators-that-do-not-propagate-on-move-assignment"><span class="header-section-number">9.2</span> Fixing element types using
allocators that do not propagate on move assignment<a href="#fixing-element-types-using-allocators-that-do-not-propagate-on-move-assignment" class="self-link"></a></h2>
<p>Next, it does not hold for
<code class="sourceCode default">pmr</code> containers themselves, or
more generally, it does not hold for types that use an allocator that
does not propagate on move-assignment. We may enable relocation when
allocators are guaranteed to be always equal, but that may be a bad
choice when thinking of relocating elements (with allocator telemetry)
rather than values. By convention, types that use allocators do so by
providing a type alias member named
<code class="sourceCode default">allocator_type</code>.</p>
<p>To preserve maximum compatibility with existing containers and
allocators, we further consider a type that has an allocator that always
compares equal as-if it were propagating on move-assignment; this
behavior can be changed for an allocator that does indeed compare about
preserving allocators with elements, where such allocators store
non-salient information that they wish to retain with the allocated
element — so we might prefer to simplify the default to just
<code class="sourceCode default">propagate_on_move_assignment</code>.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>   <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">{</span> <span class="kw">typename</span> T<span class="op">::</span>allocator_type; <span class="op">}</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> container_replace_with_assignment<span class="op">&lt;</span>T<span class="op">&gt;</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">:</span> disjunction<span class="op">&lt;</span> allocator_traits<span class="op">&lt;</span>T<span class="op">::</span>allocator_type<span class="op">&gt;::</span>propagate_on_move_assignment</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>               , allocator_traits<span class="op">&lt;</span>T<span class="op">::</span>allocator_type<span class="op">&gt;::</span>allocators_always_equal<span class="op">&gt;::</span>type</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="op">{}</span>;</span></code></pre></div>
<h1 data-number="10" id="addressing-objections"><span class="header-section-number">10</span> Addressing Objections<a href="#addressing-objections" class="self-link"></a></h1>
<p>We anticipate several reasonable concerns from folks reviewing this
paper. He we address the objections we anticipate, and future updates
will add to this list as additional concerns are raised during
review.</p>
<!--

## The distinction between elements and values is invented just for this paper

...


## Why did it take so long to raise these concerns?

...
  -->
<h2 data-number="10.1" id="abi-breakage"><span class="header-section-number">10.1</span> ABI breakage<a href="#abi-breakage" class="self-link"></a></h2>
<p>In principle, there should be <strong>no</strong> ABI breakage,
although there may be a change of behavior — as would occur with any
ABI-compatible bug fix.</p>
<p>NOTE THAT THIS CLAIM IS YET TO BE REVIEWED BY THE ABI WORKING GROUP.
WE ARE DEFERRING SENDING FOR AN OPINION UNTIL LEWG HAS EXPRESSED ENOUGH
INTEREST FOR THE ABI GROUP TO SPEND TIME CONFIRMING OUR CLAIMS.</p>
<p>Specifically, nothing in this paper requires changing or adding data
members for existing library products. All the changes arise from adding
new traits, or creating types that were not previously expressible in
the language, so there should be no impact on name-mangling, ensuring
new and old code can link together, subject to the behavior change
mentioned above (ODR violation?).</p>
<p>Readers with a long member may remember <span class="citation" data-cites="P0181R1">[<a href="#ref-P0181R1" role="doc-biblioref">P0181R1</a>]</span> by the same author made similar
claims, yet was withdrawn from the C++17 FDIS due to the late discovery
or surprise ABI breakage. Why is this case different?</p>
<p>The key difference is that that the default order proposal changed
the specification for a default template argument, to use a metafunction
that produced exactly the same result for all existing code. As the
class templates always produced the same instantiation using exactly the
same argument lists, the expectation was that the mangling of those
types should be unaffected. This assumption was correct.</p>
<p>What had not been considered was that the mangling of the formula to
produce the default argument was including in the mangling of function
templates taking arguments of those container types. This additional
mangling is not necessary and was a surprise to many. However, it does
help an implementation diagnose undefined behavior when a template
instantiation may be impacted by additional templates, such as whether a
specialization for the
<code class="sourceCode default">default_order</code> template might be
seen by one TU, but not another. This ABI-check would catch cases that
seemed to produce the same type, but for different reasons.</p>
<p>The library proposal before us has no such impact, even on default
template arguments in the standard library. Any impact that would affect
internal dispatch as a library implementation detail can be avoided by
the use of <code class="sourceCode default">if constexpr</code> to
perform any additional dispatching within the current ABI bounds. Hence,
there should be no impact reminiscent of the older paper.</p>
<h2 data-number="10.2" id="breaking-changes-of-behavior"><span class="header-section-number">10.2</span> Breaking changes of behavior<a href="#breaking-changes-of-behavior" class="self-link"></a></h2>
<p>This proposal could change the runtime behavior of existing programs.
Is the proposed cure worse than the original problem? Here was address
each known change of behavior for a currently valid program.</p>
<h3 data-number="10.2.1" id="really-old-code-is-generally-not-maintained-so-can-be-hard-to-audit"><span class="header-section-number">10.2.1</span> Really old code is generally
not maintained so can be hard to audit<a href="#really-old-code-is-generally-not-maintained-so-can-be-hard-to-audit" class="self-link"></a></h3>
<p>Note that there are exactly no changes of behavior for code written
to the C++98 and C++03 standards. To enable the change of behavior, a
type trait must be specialized by the user as different to the default.
The few changes to programs written against a later standard are tightly
targeted to containers of tuples where one of the elements is a
reference type, and containers that use allocators that do not propagate
on move assignment; we could remove those targeted changes and users
would still benefit from the rest of this proposal.</p>
<h3 data-number="10.2.2" id="containers-of-stdtuple-holding-references"><span class="header-section-number">10.2.2</span> Containers of
<code class="sourceCode default">std::tuple</code> holding references<a href="#containers-of-stdtuple-holding-references" class="self-link"></a></h3>
<p>The proposal specializes the new <code class="sourceCode default">container_relocate_with_assignment</code>
trait as <code class="sourceCode default">false_type</code> for any
<code class="sourceCode default">tuple</code> containing an element
that, in turn, specializes that trait as
<code class="sourceCode default">false_type</code>. By definition, that
set of types starts as empty, so no breakage would occur.</p>
<p>However, this proposal does extend that set of types beyond the empty
set, as there is a real desire to fix current semantics. The initial set
of types that specialize <code class="sourceCode default">container_relocate_with_assignment</code> as
<code class="sourceCode default">false_type</code> is limited to all
reference types; tuples that have no reference-type template arguments
have no change of behavior, or ABI. For users who believe they are
correctly depending on the current specification for this case, we refer
to the second (motivating example)[#ex.vectorvvector], which
demonstrates that the current behavior is surprisingly inconsistent and
likely does not actually behave as users expect in all circumstance
—acknowledging that determined users who consistently
<code class="sourceCode default">reserve</code> space for their
<code class="sourceCode default">vector</code> and never exceed that may
be out there.</p>
<p>The second set of types that specialize <code class="sourceCode default">container_relocate_with_assignment</code> as
<code class="sourceCode default">false_type</code> is types that have an
<code class="sourceCode default">allocator_type</code> typedef-name for
an allocator type that does not propagate on move-assignment. In the
standard library, that set is limited to containers using
<code class="sourceCode default">std::pmr::polymorphic_allocator</code>.
Note that
<code class="sourceCode default">std::pmr::polymorphic_allocator</code>
itself is not such a type, so tuples of allocators rather than
containers have no change of behavior.</p>
<!--
### Containers using an allocator that does not propagate on move-assignment

...
  -->
<h2 data-number="10.3" id="potential-for-a-negative-impact-on-runtime-performance"><span class="header-section-number">10.3</span> Potential for a negative
impact on runtime performance<a href="#potential-for-a-negative-impact-on-runtime-performance" class="self-link"></a></h2>
<p>There are two aspects to this objection. First we observe that after
this proposal, components like <code class="sourceCode default">std::pmr::vector&lt;std::pmr::string&gt;&gt;</code>
will suffer a significant performance penalty unless we also update
<code class="sourceCode default">std::pmr::polymorphic_allcator</code>
as proposed. The problem here is that, for a conforming implementation,
that should be the expected behavior today. We retain the expected
performance for <code class="sourceCode default">pmr</code> containers
only because the current implementations are non-conforming. This paper
proposes a simple way for those containers to maintain (or enhance)
their performance, allowing vendors to fix their bugs. Once the vendors
do fix their bugs, absent this paper, there is nothing clients can do to
recover that performance.</p>
<p>The second category of reduced runtime performance is for container
elements that specialize <code class="sourceCode default">container_replace_with_assignment</code> to
<code class="sourceCode default">false_type</code>. That set is very
small without users providing that specialization themselves, but as
noted above, the most impacted set of users would be allocator authors
who provide an allocator that does not propagate on move-assignment;
objects using such an allocator must be destroy/construct-ed rather than
assigned-to with the this proposal, unless the author updates their
allocator to support the new
<code class="sourceCode default">replace</code> member function.
However, that code will now have the correct semantics for a container,
and correctness is often preferable to performance. As stated, the user
would have the ability to recover all that container performance, if
appropriate, simply by adding on function to their allocator.</p>
<h2 data-number="10.4" id="container-functions-like-stderase-retain-the-original-problems"><span class="header-section-number">10.4</span> Container functions like
<code class="sourceCode default">std::erase</code> retain the original
problems<a href="#container-functions-like-stderase-retain-the-original-problems" class="self-link"></a></h2>
<p>The key to proposed behavior change is that the elements that are
managed by a container are a property of the container that is not
exposed to the outside world, while can only inspect the values. This
means the programs implemented using only the public “value” interface
will continue to behave as they do today. For example, the container
<code class="sourceCode default">erase</code> function uses the
<code class="sourceCode default">remove</code> or
<code class="sourceCode default">remove_if</code> standard algorithm to
efficiently remove elements from a
<code class="sourceCode default">vector</code> by first shuffling down
the values, rather than trying to call
<code class="sourceCode default">erase</code> on each element, where
with a <code class="sourceCode default">std::list</code> the container
function used the public member function of
<code class="sourceCode default">list</code> to erase just the specified
elements.</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong><code class="sourceCode default">std::list</code></strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode default">std::vector</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;list&gt;</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;tuple&gt;</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> Elem <span class="op">=</span> std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;</span>;</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> a<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span><span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>, <span class="dv">8</span>, <span class="dv">9</span> <span class="op">}</span>;</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> report_a <span class="op">=</span> <span class="op">[&amp;]()</span> <span class="op">{</span></span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> <span class="kw">const</span> <span class="op">&amp;</span> i <span class="op">:</span> a<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> i;</span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> report <span class="op">=</span> <span class="op">[](</span><span class="kw">auto</span> <span class="kw">const</span> <span class="op">&amp;</span> view<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> <span class="kw">const</span> <span class="op">&amp;</span> i <span class="op">:</span> view<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>i<span class="op">)</span>;</span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb16-21"><a href="#cb16-21" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb16-22"><a href="#cb16-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb16-23"><a href="#cb16-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-24"><a href="#cb16-24" aria-hidden="true" tabindex="-1"></a>    report_a<span class="op">()</span>;                          <span class="co">// 0123456789</span></span>
<span id="cb16-25"><a href="#cb16-25" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>list<span class="op">&lt;</span>Elem<span class="op">&gt;</span> lst <span class="op">=</span> <span class="op">{</span>a<span class="op">[</span><span class="dv">1</span><span class="op">]</span>,a<span class="op">[</span><span class="dv">3</span><span class="op">]</span>,a<span class="op">[</span><span class="dv">5</span><span class="op">]</span>,a<span class="op">[</span><span class="dv">7</span><span class="op">]</span>,a<span class="op">[</span><span class="dv">9</span><span class="op">]</span> <span class="op">}</span>;</span>
<span id="cb16-26"><a href="#cb16-26" aria-hidden="true" tabindex="-1"></a>    report_a<span class="op">()</span>;                          <span class="co">// 0123456789</span></span>
<span id="cb16-27"><a href="#cb16-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-28"><a href="#cb16-28" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> value <span class="op">=</span> <span class="dv">3</span>;</span>
<span id="cb16-29"><a href="#cb16-29" aria-hidden="true" tabindex="-1"></a>    erase<span class="op">(</span>lst, Elem<span class="op">(</span>value<span class="op">))</span>;</span>
<span id="cb16-30"><a href="#cb16-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-31"><a href="#cb16-31" aria-hidden="true" tabindex="-1"></a>    report<span class="op">(</span>lst<span class="op">)</span>;                         <span class="co">// 1579</span></span>
<span id="cb16-32"><a href="#cb16-32" aria-hidden="true" tabindex="-1"></a>    report_a<span class="op">()</span>;                          <span class="co">// 0123456789</span></span>
<span id="cb16-33"><a href="#cb16-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-34"><a href="#cb16-34" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb16-35"><a href="#cb16-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;tuple&gt;</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;vector&gt;</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> Elem <span class="op">=</span> std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="op">&amp;&gt;</span>;</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> a<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span><span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>, <span class="dv">8</span>, <span class="dv">9</span> <span class="op">}</span>;</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> report_a <span class="op">=</span> <span class="op">[&amp;]()</span> <span class="op">{</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> <span class="kw">const</span> <span class="op">&amp;</span> i <span class="op">:</span> a<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> i;</span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> report <span class="op">=</span> <span class="op">[](</span><span class="kw">auto</span> <span class="kw">const</span> <span class="op">&amp;</span> view<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> <span class="kw">const</span> <span class="op">&amp;</span> i <span class="op">:</span> view<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> std<span class="op">::</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>i<span class="op">)</span>;</span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a>    report_a<span class="op">()</span>;                            <span class="co">// 0123456789</span></span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>Elem<span class="op">&gt;</span> vec <span class="op">=</span> <span class="op">{</span>a<span class="op">[</span><span class="dv">1</span><span class="op">]</span>,a<span class="op">[</span><span class="dv">3</span><span class="op">]</span>,a<span class="op">[</span><span class="dv">5</span><span class="op">]</span>,a<span class="op">[</span><span class="dv">7</span><span class="op">]</span>,a<span class="op">[</span><span class="dv">9</span><span class="op">]</span> <span class="op">}</span>;</span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a>    report_a<span class="op">()</span>;                            <span class="co">// 0123456789</span></span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> value <span class="op">=</span> <span class="dv">3</span>;</span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true" tabindex="-1"></a>    erase<span class="op">(</span>vec, Elem<span class="op">(</span>value<span class="op">))</span>;</span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-31"><a href="#cb17-31" aria-hidden="true" tabindex="-1"></a>    report<span class="op">(</span>vec<span class="op">)</span>;                           <span class="co">// 1579</span></span>
<span id="cb17-32"><a href="#cb17-32" aria-hidden="true" tabindex="-1"></a>    report_a<span class="op">()</span>;                            <span class="co">// 012<span class="rm" style="color: #bf0303"><del>5</del></span>4<span class="rm" style="color: #bf0303"><del>7</del></span>6<span class="rm" style="color: #bf0303"><del>9</del></span>89</span></span>
<span id="cb17-33"><a href="#cb17-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-34"><a href="#cb17-34" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb17-35"><a href="#cb17-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>Despite not directly addressing the underlying problem in this case,
we believe this proposal is still the right direction. Frequently users
manipulate <code class="sourceCode default">vector</code>s directly,
rather than eagerly adopting every new library API that we create.
Giving users the ability to turn to the
<code class="sourceCode default">vector</code> and obtain the desired
behavior, even if less efficiently, is an important option that is not
available today — where the surprising assignment behavior is forced
upon users through both the algorithmic interface and calling members of
<code class="sourceCode default">vector</code> directly.</p>
<p>If we were more ambitious we might propose adding an
<code class="sourceCode default">if constexpr</code> test for the new
<code class="sourceCode default">container_replace_with_assignment</code>
trait in the <code class="sourceCode default">vector</code>
implementation of the container erase function; instead, we prefer to
minimize potential breakage of existing code, in the knowledge that
users would now have the ability to fix their own code.</p>
<!--

# Proposed Wording

The following wording based on the latest working draft at the time this paper
is written, [@N4958].

**Editors' note: Uncompleted wording tasks:**

* complete specification for `uninitialized_move_and_destroy`

## REVIEW NOTE FOR LEWG

THIS WORDING IS EVOLVING AND INCOMPLETE, BUT WILL GIVE EWG A FLAVOR OF THE TEXT
WE INTEND TO FINALIZE BEFORE SENDING TO LWG.  IT WILL BE INTEGRATED INTO A
SINGLE WORDING SECTION, RATHER THAN PER TOPIC, ONCE LEWG DETERMINES HOW MUCH OF
THIS PAPER, IF ANY, SHOULD PROCEED.

## Library support for Frumpy elements

We put the new trait into the `<memory>` header as its primary interaction is
through `allocator_traits`, and container implementations concerned with
allocator behavior.  This is simlar to the treatment of the `uses_allocator`
trait.

Add to the `<memory>` header synopsis in [memory.syn]{.sref}p3:

```
template <class T>
struct container_replace_with_assignment : is_move_assignable<T>::type {}

template <class T>
struct container_replace_with_assignment : bool_constant<!is_reference_v<T>> {}

template <class T>
   requires requires { typename T::allocator_type; }
struct container_replace_with_assignment<T>
  : disjunction< allocator_traits<T::allocator_type>::propagate_on_move_assignment
               , allocator_traits<T::allocator_type>::allocators_always_equal>::type
{};


// Move to <tuple> header
template <class ...TYPES>
struct container_replace_with_assignment<tuple<TYPES...>>
   : conjunction<container_replace_with_assignment<tuple<TYPES>>...>::type
{};

template <class T>
constexpr bool container_replace_with_assignment_v = container_replace_with_assignment<T>::value;
```

## New members of `allocator_traits`

WORDING TO FOLLOW FOR `relocate` AND `replace`

## New _Cpp17Requirements_ for internal relocation in a block container

...

## Library extensions for trivial relocation

The following library extensions assume the adoption of some revision of
[@P2786R2].

### `relocate`

Add to the `<memory>` header synopsis in [memory.syn]{.sref}p3:


```
// 20.2.6, explicit lifetime management template<class T>
  T* start_lifetime_as(void* p) noexcept;                                       // freestanding
template<class T>
  const T* start_lifetime_as(const void* p) noexcept;                           // freestanding
template<class T>
  volatile T* start_lifetime_as(volatile void* p) noexcept;                     // freestanding
template<class T>
  const volatile T* start_lifetime_as(const volatile void* p) noexcept;         // freestanding
template<class T>
  T* start_lifetime_as_array(void* p, size_t n) noexcept;                       // freestanding
template<class T>
  const T* start_lifetime_as_array(const void* p, size_t n) noexcept;           // freestanding
template<class T>
  volatile T* start_lifetime_as_array(volatile void* p, size_t n) noexcept;     // freestanding
template<class T>
  const volatile T* start_lifetime_as_array(const volatile void* p,
                                            size_t n) noexcept;                 // freestanding
```
::: add

```
template <class T>
   requires (is_trivially_relocatable_v<T> || is_nothrow_move_constructible_v)
         && !is_const_v<T>
constexpr
T* relocate(T* begin, T* end, T* new_location);                                 // freestanding

```
:::


Append to Append to [obj.lifetime]{.sref}:

::: add

```
template <class T>
   requires (is_trivially_relocatable_v<T> || is_nothrow_move_constructible_v)
         && !is_const_v<T>
constexpr
T* relocate(T* begin, T* end, T* new_location);
```

__Effects__: Equivalent to:

```
if constexpr (is_trivially_relocatable_v<T>) {
   return std::trivially_relocate(begin, end, new_location);
}
else if (less{}(end, new_location) || less{}(new_location + begin - end, begin)) {
   // No overlap
   uninitialized_move(begin, end, new_location);
   destroy(begin, end);
   return new_location;
}
else if (less{}(begin, new_location) {   // move-and-destroy each member, back to front
   while (T* dest = new_location + begin - end; dest != new_location) {
      ::new (--dest) T(std::move(*--end));
      destroy_at(end);
   }
   return dest;
}
else {                                  // move-and-destroy each member, front to back
   while (begin != end) {
      ::new (new_location++) T(std::move(*begin++));
      destroy_at(begin);
   }
   return new_location;
}
```

_Throws_: Nothing.

:::

## `uninitialized_move_and_destroy` as a non-optimizing algorithm

`uninitialized_move_and_destroy` is directly inspired by
`uninitialized_relocate` in [@P1144R8] and the `uninitialized_move` family of
algorithms in the standard.  This functionality is entirely separable into a
pure library proposal, as it does not rely on any of our language extension
features.  It is proposed purely for feature parity with [@P1144R8].

The function name, `uninitialized_move_and_destroy`, is chosen to provide a
clear hint at what the operation does.  We might have preferred
`uninitialized_move_construct_and_destroy` as more descriptive, but following
the naming of `uninitialized_move`, we take `uninitialized` as sufficient
information that the output range will be populated by move constructors, as
there cannot be a live object as an alternative to assign to.

Compared to the proposed functions with `relocate` in their name, these
overloads explicitly call the move constructor, and then the destructor of the
source, so element types must support those operations, just as in [@P1144R8].
They are specified as library algorithms using iterators rather than simple
pointers.  They also have a precondition excluding overlapping ranges.

We note that blanket wording for clause [specialized.algorithms.general]{.sref}
guarantees all constructed objects will be destroyed if an exception is thrown,
but we add a _Remarks_ element to ensure that the source range honors its
guarantee to destroy all elements in such cases as well.

The `uninitialized_move` family inspires the full range of overloads, for
parallel algorithms, `std::ranges`, and [iterator, length) sequences.

Contrasting [@P1144R8] and `uninitialized_move`, our design requires forward
iterators for the input sequence, as we are modifying the source elements by
moving out, and then destroying them.


### `uninitialized_move_and_destroy`  [uninitialized.move.and.destroy]

Add to the `<memory>` header synopsis in [memory.syn]{.sref}p3:

```
// 27.11, specialized algorithms
// 27.11.2, special memory concepts

// ...

template<class InputIterator, class NoThrowForwardIterator>
NoThrowForwardIterator uninitialized_move(InputIterator first,                  // freestanding
                                          InputIterator last,
                                          NoThrowForwardIterator result);
template<class ExecutionPolicy, class ForwardIterator, class NoThrowForwardIterator>
NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec,               // see 27.3.5
                                          ForwardIterator first, ForwardIterator last,
                                          NoThrowForwardIterator result);
template<class InputIterator, class Size, class NoThrowForwardIterator>
  pair<InputIterator, NoThrowForwardIterator>
    uninitialized_move_n(InputIterator first, Size n,                           // freestanding
                         NoThrowForwardIterator result);
template<class ExecutionPolicy, class ForwardIterator, class Size,
         class NoThrowForwardIterator>
  pair<ForwardIterator, NoThrowForwardIterator>
    uninitialized_move_n(ExecutionPolicy&& exec,                                // see 27.3.5
                         ForwardIterator first, Size n, NoThrowForwardIterator result);
namespace ranges {
  template<class I, class O>
    using uninitialized_move_result = in_out_result<I, O>;                      // freestanding
  template<forward_iterator I, sentinel_for<I> S1,
           @_nothrow-forward-iterator_@ O, @_nothrow-sentinel-for_@ <O> S2>
    requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
      uninitialized_move_result<I, O>
        uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast);             // freestanding
  template<forward_range IR, @_nothrow-forward-range_@ OR>
    requires constructible_from<range_value_t<OR>, range_rvalue_reference_t<IR>>
      uninitialized_move_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
        uninitialized_move(IR&& in_range, OR&& out_range);                      // freestanding

  template<class I, class O>
    using uninitialized_move_n_result = in_out_result<I, O>;                    // freestanding
  template<forward_iterator I,
           @_nothrow-forward-iterator_@ O, @_nothrow-sentinel-for_@ <O> S>
    requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
      uninitialized_move_n_result<I, O>
        uninitialized_move_n(I ifirst, iter_difference_t<I> n,
                             O ofirst, S olast);                                // freestanding
}

```

::: add

```
template<class ForwardIterator, class NoThrowForwardIterator>
NoThrowForwardIterator uninitialized_move_and_destroy(ForwardIterator first,    // freestanding
                                                      ForwardIterator last,
                                                      NoThrowForwardIterator result);
template<class ExecutionPolicy, class ForwardIterator, class NoThrowForwardIterator>
NoThrowForwardIterator uninitialized_move_and_destroy(ExecutionPolicy&& exec,   // see 27.3.5
                                                      ForwardIterator first, ForwardIterator last,
                                                      NoThrowForwardIterator result);
template<class ForwardIterator, class Size, class NoThrowForwardIterator>
  pair<ForwardIterator, NoThrowForwardIterator>
    uninitialized_move_and_destroy_n(ForwardIterator first, Size n,             // freestanding
                                     NoThrowForwardIterator result);
template<class ExecutionPolicy, class ForwardIterator, class Size,
         class NoThrowForwardIterator>
  pair<ForwardIterator, NoThrowForwardIterator>
    uninitialized_move_and_destroy_n(ExecutionPolicy&& exec,                    // see 27.3.5
                                     ForwardIterator first, Size n, NoThrowForwardIterator result);

namespace ranges {
  template<class I, class O>
    using uninitialized_move_and_destroy_result = in_out_result<I, O>;          // freestanding
  template<forward_iterator I, sentinel_for<I> S1,
           @_nothrow-forward-iterator_@ O, @_nothrow-sentinel-for_@ <O> S2>
    requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
      uninitialized_move_and_destroy_result<I, O>
        uninitialized_move_and_destroy(I ifirst, S1 ilast, O ofirst, S2 olast); // freestanding
  template<forward_range IR, @_nothrow-forward-range_@ OR>
    requires constructible_from<range_value_t<OR>, range_rvalue_reference_t<IR>>
      uninitialized_move_and_destroy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
        uninitialized_move_and_destroy(IR&& in_range, OR&& out_range);          // freestanding

  template<class I, class O>
    using uninitialized_move_and_destroy_n_result = in_out_result<I, O>;        // freestanding
  template<input_iterator I,
           @_nothrow-forward-iterator_@ O, @_nothrow-sentinel-for_@ <O> S>
    requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
      uninitialized_move_and_destroy_n_result<I, O>
        uninitialized_move_and_destroy_n(I ifirst, iter_difference_t<I> n,
                                         O ofirst, S olast);                    // freestanding
}
```
:::


Add a new subclause between [uninitialized.move]{.sref} and [uninitialized.fill]{.sref}:

::: add

**`uninitialized_move_and_destroy`  [uninitialized.move.and.destroy]**

```
template<class ForwardIterator, class NoThrowForwardIterator>
NoThrowForwardIterator uninitialized_move_and_destroy(ForwardIterator first,    // freestanding
                                                      ForwardIterator last,
                                                      NoThrowForwardIterator result);
```

_Preconditions_: `destination` is not in the range [`first`, `last`).

_Effects_: Equivalent to:
```
for (; first != last; ++destination, (void)++first) {
   ::new (@_voidify_@(*destination)) iter_value_t<NoThrowForwardIterator>(*first);
   destroy_at(addressof(*first));
}
return destination;
```

_Throws_: Nothing, unless an exception is thrown by a move constructor.

_Remarks_: If an exception is thrown, all objects in both the source and
destination ranges are destroyed.

:::


::: add


```
namespace ranges {
  template<forward_iterator I, sentinel_for<I> S1,
           @_nothrow-forward-iterator_@ O, @_nothrow-sentinel-for_@ <O> S2>
    requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
    uninitialized_move_and_destroy<I, O>
      uninitialized_move_and_destroy(I ifirst, S1 ilast, O ofirst, S2 olast);   // freestanding
}
```

:::


::: add

```
namespace ranges {
  template<forward_iterator IR, @_nothrow-forward-range_@ OR>
    requires constructible_from<range_value_t<OR>, range_rvalue_reference_t<IR>>
    uninitialized_move_and_destroy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
      uninitialized_move_and_destroy(IR&& in_range, OR&& out_range);            // freestanding
}
```



```
template<class ForwardIterator, class Size, class NoThrowForwardIterator>
  pair<ForwardIterator, NoThrowForwardIterator>
    uninitialized_move_and_destroy_n(ForwardIterator first, Size n,             // freestanding
                                     NoThrowForwardIterator result);
```
:::


::: add

```
namespace ranges {
  template<forward_iterator I,
           @_nothrow-forward-iterator_@ O, @_nothrow-sentinel-for_@ <O> S>
    requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
    uninitialized_move_and_destroy_n_result<I, O>
      uninitialized_move_and_destroy_n(I ifirst, iter_difference_t<I> n,
                                       O ofirst, S olast);                      // freestanding
}
```
:::


**Editors' note: Preconditions and throws clause implicit from Effects:,
but stated for clarity while in Evolutionary groups.**

  -->
<h1 data-number="11" id="acknowledgements"><span class="header-section-number">11</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thanks to Michael Park for the pandoc-based framework used to
transform this document’s source from Markdown.</p>
<p>Thanks to ARthur O`Dwyer for inspiration for many of the awkward
cases that arose while researching trivial relocatability.</p>
<p>Thanks to Lori Hughes for reviewing this paper and providing early
editorial feedback.</p>
<h1 data-number="12" id="bibliography"><span class="header-section-number">12</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
<div id="ref-LWG1102" class="csl-entry" role="doc-biblioentry">
[LWG1102] Daniel Krügler. std::vector’s reallocation policy still
unclear. <a href="https://wg21.link/lwg1102"><div class="csl-block">https://wg21.link/lwg1102</div></a>
</div>
<div id="ref-LWG2158" class="csl-entry" role="doc-biblioentry">
[LWG2158] Nikolay Ivchenkov. Conditional copy/move in std::vector. <a href="https://wg21.link/lwg2158"><div class="csl-block">https://wg21.link/lwg2158</div></a>
</div>
<div id="ref-LWG3308" class="csl-entry" role="doc-biblioentry">
[LWG3308] Billy O’Neal III. vector and deque iterator erase invalidates
elements even when no change occurs. <a href="https://wg21.link/lwg3308"><div class="csl-block">https://wg21.link/lwg3308</div></a>
</div>
<div id="ref-LWG3758" class="csl-entry" role="doc-biblioentry">
[LWG3758] Jiang An. Element-relocating operations of std::vector and
std::deque should conditionally require Cpp17CopyInsertable in their
preconditions. <a href="https://wg21.link/lwg3758"><div class="csl-block">https://wg21.link/lwg3758</div></a>
</div>
<div id="ref-P0181R1" class="csl-entry" role="doc-biblioentry">
[P0181R1] Alisdair Meredith. 2016-06-23. Ordered By Default. <a href="https://wg21.link/p0181r1"><div class="csl-block">https://wg21.link/p0181r1</div></a>
</div>
<div id="ref-P2786R2" class="csl-entry" role="doc-biblioentry">
[P2786R2] Mungo Gill, Alisdair Meredith. 2023-06-16. Trivial
relocatability options. <a href="https://wg21.link/p2786r2"><div class="csl-block">https://wg21.link/p2786r2</div></a>
</div>
</div>
<section class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>C++23 adds
<code class="sourceCode default">std::zip</code> based on the same
property of <code class="sourceCode default">std::tuple</code>.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p>The output of this program is:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>11211aabaa</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>22222aaaaa</span></code></pre></div>
<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></li>
<li id="fn3" role="doc-endnote"><p>Prior to C++20,
<code class="sourceCode default">std::allocator</code> had a
<code class="sourceCode default">rebind</code> member template that was
inherited by our custom allocators; for older language dialects, an
additional <code class="sourceCode default">rebind</code> template must
be supplied to hide that in the base to avoid bad behavior.<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p>Prior to C++20,
<code class="sourceCode default">std::allocator</code> had a
<code class="sourceCode default">rebind</code> member template that was
inherited by our custom allocators; for older language dialects, an
additional <code class="sourceCode default">rebind</code> template must
be supplied to hide that in the base to avoid bad behavior.<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
