<!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="2024-09-26" />
  <title>Accessing object representations</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 { } 
code span.al { color: #ff0000; } 
code span.an { } 
code span.at { } 
code span.bn { color: #9f6807; } 
code span.bu { color: #9f6807; } 
code span.cf { color: #00607c; } 
code span.ch { color: #9f6807; } 
code span.cn { } 
code span.co { color: #008000; font-style: italic; } 
code span.cv { color: #008000; font-style: italic; } 
code span.do { color: #008000; } 
code span.dt { color: #00607c; } 
code span.dv { color: #9f6807; } 
code span.er { color: #ff0000; font-weight: bold; } 
code span.ex { } 
code span.fl { color: #9f6807; } 
code span.fu { } 
code span.im { } 
code span.in { color: #008000; } 
code span.kw { color: #00607c; } 
code span.op { color: #af1915; } 
code span.ot { } 
code span.pp { color: #6f4e37; } 
code span.re { } 
code span.sc { color: #9f6807; } 
code span.ss { color: #9f6807; } 
code span.st { color: #9f6807; } 
code span.va { } 
code span.vs { color: #9f6807; } 
code span.wa { color: #008000; font-weight: bold; } 
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: 2.5em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
ol {
padding-left: 2.5em;
}
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;
}

#TOC ul > li:before {
content: none;
}
#TOC > ul {
padding-left: 0;
}

.toc-section-number {
margin-right: 0.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">Accessing object
representations</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P1839R6</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-09-26</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>
      EWG, CWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Timur Doumler<br>&lt;<a href="mailto:papers@timur.audio" class="email">papers@timur.audio</a>&gt;<br>
      Krystian Stasiowski<br>&lt;<a href="mailto:sdkrystian@gmail.com" class="email">sdkrystian@gmail.com</a>&gt;<br>
      Brian Bi<br>&lt;<a href="mailto:bbi10@bloomberg.net" class="email">bbi10@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</a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">2</span> Motivation</a></li>
<li><a href="#the-problem" id="toc-the-problem"><span class="toc-section-number">3</span> The problem</a></li>
<li><a href="#history-and-context" id="toc-history-and-context"><span class="toc-section-number">4</span> History and context</a></li>
<li><a href="#non-goals" id="toc-non-goals"><span class="toc-section-number">5</span> Non-goals</a></li>
<li><a href="#proposed-solution" id="toc-proposed-solution"><span class="toc-section-number">6</span> Proposed solution</a></li>
<li><a href="#polls" id="toc-polls"><span class="toc-section-number">7</span> Polls</a></li>
<li><a href="#proposed-wording" id="toc-proposed-wording"><span class="toc-section-number">8</span> Proposed wording</a></li>
<li><a href="#known-issues" id="toc-known-issues"><span class="toc-section-number">9</span> Known issues</a></li>
<li><a href="#document-history" id="toc-document-history"><span class="toc-section-number">10</span> Document history</a></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">11</span> Acknowledgements</a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">12</span> References</a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>This paper proposes a wording fix to the C++ standard to allow read
access to the object representation (i.e. the underlying bytes) of an
object. This is valid in C, and is widely used and assumed to be valid
in C++ as well. However, in C++ this is is undefined behaviour under the
current specification.</p>
<h1 data-number="2" id="motivation"><span class="header-section-number">2</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>Consider the following program, which takes an
<code class="sourceCode cpp"><span class="dt">int</span></code> and
prints the underlying bytes of its value in hex format:</p>
<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="dt">void</span> print_hex<span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">unsigned</span> <span class="dt">char</span><span class="op">*</span> a <span class="op">=</span> <span class="op">(</span><span class="dt">unsigned</span> <span class="dt">char</span><span class="op">*)(&amp;</span>n<span class="op">)</span>;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">int</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    printf<span class="op">(</span><span class="st">&quot;%02x &quot;</span>, a<span class="op">[</span>i<span class="op">])</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  print_hex<span class="op">(</span><span class="dv">123456</span><span class="op">)</span>;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>In C, this is a valid program. On a little-endian machine where <code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">(</span><span class="dt">int</span><span class="op">)</span> <span class="op">==</span> <span class="dv">4</span></code>,
this will print <code class="sourceCode cpp"><span class="dv">40</span> e2 <span class="bn">01</span> <span class="bn">00</span></code>.
In C++, this is widely assumed to be valid as well, and this
functionality is widely used in existing code bases (think of binary
file formats, hex viewers, and many other low-level use cases).</p>
<p>However, surprisingly, in C++ this code has undefined behaviour under
the current specification. In fact, it is impossible in C++ to directly
access the object representation of an object (i.e. to read its
underlying bytes), even for built-in types such as
<code class="sourceCode cpp"><span class="dt">int</span></code>.
Instead, we would have to use <code class="sourceCode cpp">memcpy</code>
to copy the bytes into a separate array of <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>,
and access them from there.<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> However, this workaround
only works for trivially copyable types. It also directly violates one
of the fundamental principles of C++: to leave no room for a lower-level
language.</p>
<p>The goal of this paper is to provide the necessary wording fixes to
make accessing object representations such as in the code above defined
behaviour. Existing compilers already assume that this should be valid.
The goal of the paper is therefore to <em>not</em> require any changes
to existing compilers or existing code, but to legalise existing code
that already works in practice and was always intended to be valid.</p>
<h1 data-number="3" id="the-problem"><span class="header-section-number">3</span> The problem<a href="#the-problem" class="self-link"></a></h1>
<p>The cast to <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span><span class="op">*</span></code>,
which performs a <code class="sourceCode cpp"><span class="kw">reinterpret_cast</span></code>,
is fine, because
<code class="sourceCode cpp"><span class="dt">char</span></code>, <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>,
and
<code class="sourceCode cpp">std<span class="op">::</span>byte</code>
can alias any other type, so we do not violate the rules for type
punning. However, with the current wording, this cast does <em>not</em>
yield a pointer to the first element of
<code class="sourceCode cpp">n</code>’s object representation (i.e. a
pointer to a byte), and in fact it is currently impossible in C++ to
obtain such a pointer. This is because this particular <code class="sourceCode cpp"><span class="kw">reinterpret_cast</span></code>
is exactly equivalent to <code class="sourceCode cpp"><span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">unsigned</span> <span class="dt">char</span><span class="op">*&gt;(</span><span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">void</span><span class="op">*&gt;(&amp;</span>n<span class="op">))</span></code>
as per §<span>7.6.1.10
<a href="https://wg21.link/N4988#expr.reinterpret.cast">[expr.reinterpret.cast]</a><a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a></span>p7, and as such,
§<span>7.6.1.9
<a href="https://wg21.link/N4988#expr.static.cast">[expr.static.cast]</a></span>p13
dictates that the value of the pointer is unchanged and therefore it
points to the original object (the
<code class="sourceCode cpp"><span class="dt">int</span></code>). When
<code class="sourceCode cpp">a</code> is dereferenced, the behaviour is
undefined as per §<span>7.1
<a href="https://wg21.link/N4988#expr.pre">[expr.pre]</a></span>p4
because the value of the resulting expression would <em>not</em> be the
value of the first byte, but the value of the whole
<code class="sourceCode cpp"><span class="dt">int</span></code> object
(123456), which is not a value representable by <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>.</p>
<p>Further, even if we ignore this issue,
<code class="sourceCode cpp">a</code> does not point to an array of
<code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>,
because such an array has never been created, and therefore pointer
arithmetic on <code class="sourceCode cpp">a</code> has undefined
behaviour. An object representation as defined by §<span>6.8
<a href="https://wg21.link/N4988#basic.types">[basic.types]</a></span>p4
is merely a <em>sequence</em> of <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>
objects, not an array, and is therefore unsuitable for pointer
arithmetic. No array is ever created explicitly, and no operation is
being called in the above code that would implicitly create an array,
since casts are not operations that implicitly create objects as per
§<span>6.7.2
<a href="https://wg21.link/N4988#intro.object">[intro.object]</a></span>p11.</p>
<p>It is possible to explicitly start the lifetime of an array of <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>
in the storage occupied by <code class="sourceCode cpp">n</code> whose
values are the values of <code class="sourceCode cpp">n</code>’s object
representation. This can be done by using
<code class="sourceCode cpp">std<span class="op">::</span>memmove</code>
to copy <code class="sourceCode cpp">n</code> to itself or, since C++23,
calling the <code class="sourceCode cpp">std<span class="op">::</span>start_lifetime_as_array</code>
function. However, these operations are destructive: because the new
array reuses the storage of <code class="sourceCode cpp">n</code>,
<code class="sourceCode cpp">n</code>’s lifetime ends when the new array
comes into existence. In a multithreaded program, this operation can
race with another operation that reads
<code class="sourceCode cpp">n</code>, and is therefore less useful than
copying the bytes into a separate array in order to examine them.</p>
<h1 data-number="4" id="history-and-context"><span class="header-section-number">4</span> History and context<a href="#history-and-context" class="self-link"></a></h1>
<p>The intent of CWG has always been that the above code should work, as
exemplified by <span class="citation" data-cites="CWG1314">[<a href="https://wg21.link/cwg1314" role="doc-biblioref">CWG1314</a>]</span>, in which it is stated that
access to the object representation is intended to be well-defined.
Further, it seems that the above code actually <em>did</em> work until
C++17, when <span class="citation" data-cites="P0137R1">[<a href="https://wg21.link/p0137r1" role="doc-biblioref">P0137R1</a>]</span> was accepted. This proposal
fixed an unrelated core issue and included a change to how pointers
work, notably that they point to objects, rather than just representing
an address. It seems that the proposal neglected to add any provisions
to allow access to the object representation of an object, and thus
inadvertently broke this functionality. Therefore, this paper is a
defect report, not a proposal of a new feature.</p>
<p>Notably, there are even standard library facilities that directly use
this functionality and cannot be implemented in standard C++ without
fixing it. One such facility is <code class="sourceCode cpp">std<span class="op">::</span>as_bytes</code>
(introduced in C++20), which obtains a <code class="sourceCode cpp">std<span class="op">::</span>span<span class="op">&lt;</span><span class="kw">const</span> std<span class="op">::</span>byte<span class="op">&gt;</span></code>
view to the object representation of the elements of another span. Now,
we do have a few “magic” functions in the C++ standard library that
cannot be implemented in standard C++, but reading the underlying bytes
of an object is such basic functionality that it should not fall into
this category.</p>
<h1 data-number="5" id="non-goals"><span class="header-section-number">5</span> Non-goals<a href="#non-goals" class="self-link"></a></h1>
<p>This paper does not propose to make in-place modification of the
object representation valid, i.e. <em>writing</em> into the underlying
bytes, only <em>reading</em> them. The following code will still have
undefined behaviour:</p>
<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="dt">void</span> increment_first_byte<span class="op">(</span><span class="dt">int</span><span class="op">*</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span><span class="op">*</span> a <span class="op">=</span> <span class="kw">reinterpret_cast</span><span class="op">&lt;</span><span class="dt">char</span><span class="op">*&gt;(</span>n<span class="op">)</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">++(*</span>a<span class="op">)</span>;</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>It may be desirable to allow such code as well. However, unlike
reading the object representation, the effect of modifying it has never
been specified in C++, so specifying it would be a new feature, not a
defect report. Therefore, CWG gave the guidance to reduce the scope of
this paper to reading only, and propose the modifying case in a separate
paper (not yet published).</p>
<p>This paper also does not propose to subvert existing type punning
rules in any way. The proposed changes will not allow type punning
between two different types where it was not previously allowed, such as
between <code class="sourceCode cpp"><span class="dt">int</span></code>
and <code class="sourceCode cpp"><span class="dt">float</span></code>
(this should be done using <code class="sourceCode cpp">std<span class="op">::</span>bit_cast</code>). It
only allows type punning to
<code class="sourceCode cpp"><span class="dt">char</span></code>, <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>,
and
<code class="sourceCode cpp">std<span class="op">::</span>byte</code>,
which are already allowed to alias any other type.</p>
<p>We also do not propose to make accessing the object representation
work for <em>all</em> types in C++, only for types that are currently
guaranteed to occupy contiguous bytes of storage, that is, for trivially
copyable or standard-layout types as per §<span>6.7.2
<a href="https://wg21.link/N4988#intro.object">[intro.object]</a></span>p8.
On the one hand, this is unnecessarily restrictive: in practice, any
sane implementation will have complete objects, array elements, and
member subobjects occupying contiguous memory, as the only reason an
object would need to be non-contiguous would be if it was a virtual base
subobject. On the other hand, making more objects contiguous (and
therefore, their object representations accessible) is not in scope for
this paper, and is instead tackled in a separate proposal <span class="citation" data-cites="P1945R0">[<a href="https://wg21.link/p1945r0" role="doc-biblioref">P1945R0</a>]</span>.</p>
<h1 data-number="6" id="proposed-solution"><span class="header-section-number">6</span> Proposed solution<a href="#proposed-solution" class="self-link"></a></h1>
<p>For an object <em>a</em> of type
<code class="sourceCode cpp">T</code>, we propose to change the
definition of <em>object representation</em> to be considered an array
of <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>,
and not merely a <em>sequence</em> of <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>
objects, if <code class="sourceCode cpp">T</code> is a type that
occupies contiguous bytes of storage. We propose that this object
representation should be an object in its own right, occupying the same
storage as <em>a</em> and having the same lifetime. This will make
pointer arithmetic work with a pointer to an element of the object
representation.</p>
<p>To avoid an infinite recursion of nested object representations, we
further specify that an array of <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>
acts as its own object representation. We also need to prevent implicit
object creation <span class="citation" data-cites="P0593R6">[<a href="https://wg21.link/p0593r6" role="doc-biblioref">P0593R6</a>]</span> within object
representations.</p>
<p>We further propose that obtaining a pointer to the object
representation should be possible through the use of a cast to
<code class="sourceCode cpp"><span class="dt">char</span></code>, <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>,
or
<code class="sourceCode cpp">std<span class="op">::</span>byte</code>,
and allow this pointer to be cast back to a pointer to its respective
object. For this, we need to make the appropriate changes to the
specification of
<code class="sourceCode cpp"><span class="kw">static_cast</span></code>
and to make <em>a</em> pointer-interconvertible with its own object
representation as well as with the first element thereof. We need to do
this in a way that preserves <code class="sourceCode cpp"><span class="kw">reinterpret_cast</span></code>’s
equivalence with
<code class="sourceCode cpp"><span class="kw">static_cast</span></code>
with respect to converting object pointers. Simultaneously, if multiple
pointer-interconvertible objects exist, we need to specify which one is
chosen.</p>
<p>Additionally, we need to make reading an object representation
through a pointer to
<code class="sourceCode cpp"><span class="dt">char</span></code> or
<code class="sourceCode cpp">std<span class="op">::</span>byte</code>
well-defined, even though it points to an element of the object
representation which is of type <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>.
In these cases, we must allow for the type of the expression to differ
from that of the object pointed to.</p>
<p>We also need to say something about the values of the elements of an
object representation. We propose that for objects of type
<code class="sourceCode cpp"><span class="dt">char</span></code>, <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>,
and
<code class="sourceCode cpp">std<span class="op">::</span>byte</code>,
the value of each element is the value of the object it represents. For
all other types, the values of the elements of the object representation
are unspecified. It seems extremely difficult to specify for the general
case what the value of each element would be, but it is also
unnecessary, since our goal is only to make reading the elements
well-defined, not to specify a particular result (which won’t be the
same across platforms).</p>
<p>Finally, multiple objects may occupy the same storage, in which case
the objects’ respective object representations will overlap. We must
therefore adjust the specification of
<code class="sourceCode cpp">std<span class="op">::</span>launder</code>
to define which object it will return a pointer to.</p>
<p>In order to preserve reachability-based restrictions that currently
exist in C++, we propose that when an object <em>o1</em> is nested
within an object <em>o2</em>, the object representation <em>a1</em> of
<em>o1</em> is also nested within the object representation <em>a2</em>
of <em>o2</em>, but in typical cases, each element of <em>a1</em> is a
different object from the element of <em>a2</em> that occupies the same
storage. Therefore, a pointer to an element of an object representation
that is obtained by a <code class="sourceCode cpp"><span class="kw">reinterpret_cast</span></code>
applied to a pointer to <em>a1</em> cannot be used to “escape” from the
bytes of <em>a1</em> and reach bytes of <em>a2</em> that exist outside
<em>a1</em>.<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<h1 data-number="7" id="polls"><span class="header-section-number">7</span> Polls<a href="#polls" class="self-link"></a></h1>
<p><strong>EWGI</strong></p>
<p>Should accessing the object representation be defined behavior?</p>
<blockquote>
<p>Unanimous consent</p>
</blockquote>
<p>Forward P1839R1 as presented to EWG, recommending that this be a core
issue?</p>
<blockquote>
<p>Unanimous consent</p>
</blockquote>
<p><strong>EWG</strong></p>
<p>It should be possible to access the entire object representation
through a pointer to a char-like type as a DR.</p>
<blockquote>
<table>
<thead>
<tr class="header">
<th style="text-align: center;"><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th style="text-align: center;"><div style="text-align:center">
<strong>F</strong>
</div></th>
<th style="text-align: center;"><div style="text-align:center">
<strong>N</strong>
</div></th>
<th style="text-align: center;"><div style="text-align:center">
<strong>A</strong>
</div></th>
<th style="text-align: center;"><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">10</td>
<td style="text-align: center;">8</td>
<td style="text-align: center;">2</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">0</td>
</tr>
</tbody>
</table>
</blockquote>
<blockquote>
<p>Consensus</p>
</blockquote>
<h1 data-number="8" id="proposed-wording"><span class="header-section-number">8</span> Proposed wording<a href="#proposed-wording" class="self-link"></a></h1>
<p>The reported issue is intended as a defect report with the proposed
resolution as follows. The effect of the wording changes should be
applied in implementations of all previous versions of C++ where they
apply. The proposed changes are relative to the C++ working draft <span class="citation" data-cites="N4988">[<a href="https://wg21.link/n4988" role="doc-biblioref">N4988</a>]</span>.</p>
<p>Modify §<span>6.7.2
<a href="https://wg21.link/N4988#intro.object">[intro.object]</a></span>p4
as follows:</p>
<blockquote>
<p>An object <em>a</em> is <em>nested within</em> another object
<em>b</em> if</p>
<ul>
<li><em>a</em> is a subobject of <em>b</em>, or</li>
<li><em>b</em> provides storage for <em>a</em>, or</li>
<li><span class="add" style="color: #006e28"><ins><em>a</em> and
<em>b</em> are the object representations of two objects <em>o1</em> and
<em>o2</em>, where <em>o1</em> is nested within <em>o2</em>,
or</ins></span></li>
<li>there exists an object <em>c</em> where <em>a</em> is nested within
<em>c</em>, and <em>c</em> is nested within <em>b</em>.</li>
</ul>
<div class="add" style="color: #006e28">
<p>[<em>Note</em>: An object representation is not a subobject of any
other object representation. —<em>end note</em>]</p>
</div>
</blockquote>
<p>Modify §<span>6.7.2
<a href="https://wg21.link/N4988#intro.object">[intro.object]</a></span>p10
as follows:</p>
<blockquote>
<p>Unless an object is a bit-field or a subobject of zero size, the
address of that object is the address of the first byte it occupies. Two
objects with overlapping lifetimes that are not bit-fields may have the
same address if</p>
<ul>
<li>one is nested within the other,</li>
<li>at least one is a subobject of zero size and they are not of similar
types ([conv.qual]),<span class="rm" style="color: #bf0303"><del>or</del></span></li>
<li><span class="add" style="color: #006e28"><ins>at least one is an
element of an object representation, or</ins></span></li>
<li>they are both potentially non-unique objects;</li>
</ul>
<p>otherwise, they have distinct addresses and occupy disjoint bytes of
storage.</p>
</blockquote>
<p>Modify §<span>6.7.2
<a href="https://wg21.link/N4988#intro.object">[intro.object]</a></span>p14
as follows:</p>
<blockquote>
<p>Except during constant evaluation, an operation that begins the
lifetime of an array of <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>
or <code class="sourceCode cpp">std<span class="op">::</span>byte</code>
<span class="add" style="color: #006e28"><ins>other than a synthesized
object representation ([basic.types.general])</ins></span> implicitly
creates objects within the region of storage occupied by the array.</p>
</blockquote>
<p>Insert a new paragraph after §<span>6.7.3
<a href="https://wg21.link/N4988#basic.life">[basic.life]</a></span>p3
as follows:</p>
<blockquote>
<p>The lifetime of a reference begins when its initialization is
complete. The lifetime of a reference ends as if it were a scalar object
requiring storage.</p>
</blockquote>
<blockquote>
<p>[<em>Note 1</em>: [class.base.init] describes the lifetime of base
and member subobjects. —<em>end note</em>]</p>
</blockquote>
<blockquote>
<p><span class="add" style="color: #006e28"><ins>The lifetime of the
elements of a synthesized object representation of an object begins when
the lifetime of the object begins. For class types, the lifetime of the
elements of the synthesized object representation ends when the
destruction of the object is completed; otherwise, the lifetime ends
when the object is destroyed.</ins></span></p>
</blockquote>
<p>Modify §<span>6.8.1
<a href="https://wg21.link/N4988#basic.types.general">[basic.types.general]</a></span>p4
as follows and add two paragraphs after it:</p>
<blockquote>
<p>The <em>object representation</em> of a complete object type
<code class="sourceCode cpp">T</code> is the sequence of <em>N</em>
<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">unsigned char</code></span>
objects</del></span><span class="add" style="color: #006e28"><ins>bytes</ins></span> taken up by a
non-bit-field complete object of type
<code class="sourceCode cpp">T</code>, where <em>N</em> equals <code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">(</span>T<span class="op">)</span></code>.
The <em>value representation</em> of a type
<code class="sourceCode cpp">T</code> is the set of bits in the object
representation of <code class="sourceCode cpp">T</code> that participate
in representing a value of type <code class="sourceCode cpp">T</code>.
The object and value representation of a non-bit-field complete object
of type <span class="add" style="color: #006e28"><ins><em>cv</em></ins></span>
<code class="sourceCode cpp">T</code> are the bytes and bits,
respectively, of the object corresponding to the object and value
representation of its type<span class="add" style="color: #006e28"><ins>; the object representation is considered to
be an array of <em>N</em> <em>cv</em>
<span><code class="sourceCode default">unsigned char</code></span> if
the object occupies contiguous bytes of storage
([intro.object])</ins></span>. The object representation of a bit-field
object is the sequence of <code class="sourceCode cpp">N</code> bits
taken up by the object, where <code class="sourceCode cpp">N</code> is
the width of the bit-field (11.4.10). The value representation of a
bit-field object is the set of bits in the object representation that
participate in representing its value. Bits in the object representation
of a type or object that are not part of the value representation are
padding bits. For trivially copyable types, the value representation is
a set of bits in the object representation that determines a value,
which is one discrete element of an implementation-defined set of
values.</p>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<p>For an object <em>o</em> with type <em>cv</em>
<code class="sourceCode default">T</code> whose object representation is
an array <em>A</em>:</p>
<ul>
<li>If <em>o</em> is a complete object of type “array of <em>cv</em>
<code class="sourceCode default">unsigned char</code>”, then <em>A</em>
is <em>o</em>.</li>
<li>Otherwise, if <em>o</em> is the sole element of a complete object
<em>B</em> of type “array of 1 <em>cv</em>
<code class="sourceCode default">unsigned char</code>”, then <em>A</em>
is <em>B</em>.</li>
<li>Otherwise, <em>A</em> is said to be a <em>synthesized object
representation</em>, and is distinct from any object that is not an
object representation.
<ul>
<li>If <em>o</em> is of type <em>cv</em>
<code class="sourceCode default">char</code>, <em>cv</em>
<code class="sourceCode default">unsigned char</code>, or <em>cv</em>
<code class="sourceCode default">std::byte</code>, then the value of the
sole element of <em>A</em> is the value of <em>o</em>.</li>
<li>Otherwise, if <em>o</em> is an array whose element type is
<em>cv</em> <code class="sourceCode default">char</code>, <em>cv</em>
<code class="sourceCode default">unsigned char</code>, or <em>cv</em>
<code class="sourceCode default">std::byte</code>, then the value of
each element of <em>A</em> is that of the corresponding element of
<em>o</em>.</li>
<li>Otherwise, for each bit <em>b</em> in <em>o</em>, let <em>p(b)</em>
be the smallest subobject of <em>o</em> that contains <em>b</em>. If
<em>p(b)</em> is not within its lifetime or has an indeterminate value,
or if <em>b</em> is not part of the value representation of
<em>p(b)</em>, then the bit of <em>A</em> corresponding to <em>b</em>
has indeterminate value. Otherwise, if <em>b</em> has an erroneous
value, then the bit of <em>A</em> corresponding to <em>b</em> has an
erroneous value. Otherwise, the bit of <em>A</em> corresponding to
<em>b</em> has an unspecified value.</li>
</ul></li>
</ul>
<p>[<em>Note:</em> An object representation is always a complete object.
—<em>end note</em>]</p>
<p>For a non-bit-field subobject <em>o</em> that occupies contiguous
bytes of storage and has type <code class="sourceCode default">T</code>,
other than a potentially-overlapping subobject ([intro.object]), the
object representation is an array that is defined by the above rules as
if <em>o</em> were a complete object of size
<code class="sourceCode default">sizeof(T)</code>.</p>
</blockquote>

</div>
<p><em>Drafting note:</em> It’s not entirely clear why
potentially-overlapping subobjects couldn’t be allowed here; reading
from the object representation of a potentially-overlapping subobject
doesn’t seem to pose the same problems as writing to it. But since
potentially-overlapping subobjects were already carved out by <span class="citation" data-cites="CWG43">[<a href="https://wg21.link/cwg43" role="doc-biblioref">CWG43</a>]</span>, even as the source of a copy, it
seems wise to repeat the restriction here unless CWG is certain that the
restriction is not needed.</p>
<p>Modify §<span>6.8.4
<a href="https://wg21.link/N4988#basic.compound">[basic.compound]</a></span>p5
as follows:</p>
<blockquote>
<p>Two objects <em>a</em> and <em>b</em> are
<em>pointer-interconvertible</em> if:</p>
<ul>
<li>they are the same object, or</li>
<li>one is a union object and the other is a non-static data member of
that object ([class.union]), or</li>
<li>one is a standard-layout class object and the other is the first
non-static data member of that object or any base class subobject of
that object ([class.mem]), or</li>
<li><span class="add" style="color: #006e28"><ins>one is the object
representation of the other, or the first element thereof,
or</ins></span></li>
<li>there exists an object <em>c</em> such that <em>a</em> and
<em>c</em> are pointer-interconvertible, and <em>c</em> and <em>b</em>
are pointer-interconvertible.</li>
</ul>
<p>If two objects are pointer-interconvertible, then they have the same
address<span class="rm" style="color: #bf0303"><del>, and it is possible
to obtain a pointer to one from a pointer to the other via a
<span><code class="sourceCode default">reinterpret_cast</code></span>
([expr.reinterpret.cast])</del></span>.<br />
<span class="add" style="color: #006e28"><ins>[<em>Note</em>: A
<span><code class="sourceCode default">reinterpret_cast</code></span>
([expr.reinterpret.cast]) never converts a pointer to <em>a</em> to a
pointer to <em>b</em> unless <em>a</em> and <em>b</em> are
pointer-interconvertible. —<em>end note</em>]</ins></span><br />
[<em>Note</em>: An array object and its first element are not
pointer-interconvertible, even though they have the same address<span class="add" style="color: #006e28"><ins>, unless the array is an object
representation</ins></span>. —<em>end note</em>]</p>
</blockquote>
<p>Modify §<span>7.3.2
<a href="https://wg21.link/N4988#conv.lval">[conv.lval]</a></span>p3.4,
as amended by the proposed resolution of <span class="citation" data-cites="CWG2901">[<a href="https://wg21.link/cwg2901" role="doc-biblioref">CWG2901</a>]</span>, as follows:</p>
<blockquote>
<ul>
<li>Otherwise, the object indicated by the glvalue is read
([defns.access]). Let <em>V</em> be the value contained in the object.
If <code class="sourceCode cpp">T</code> is an integer type <span class="add" style="color: #006e28"><ins>or <em>cv</em>
<span><code class="sourceCode default">std::byte</code></span></ins></span>,
the prvalue result is the value of type
<code class="sourceCode cpp">T</code> congruent ([basic.fundamental]) to
<em>V</em>, and <em>V</em> otherwise. […]</li>
</ul>
</blockquote>
<p>Modify §<span>7.6.1.9
<a href="https://wg21.link/N4988#expr.static.cast">[expr.static.cast]</a></span>p13
as follows:</p>
<blockquote>
<p>[…] Otherwise, if the original pointer value points to an object
<em>a</em>, <span class="rm" style="color: #bf0303"><del>and there is an
object <em>b</em> of type similar to
<span><code class="sourceCode default">T</code></span> that is
pointer-interconvertible ([basic.compound]) with <em>a</em>, the result
is a pointer to <em>b</em>. Otherwise, the pointer value is unchanged by
the conversion.</del></span><span class="add" style="color: #006e28"><ins>let <em>S</em> be the set of objects that
are pointer-interconvertible with <em>a</em> and have type similar to
<span><code class="sourceCode default">T</code></span>.</ins></span></p>
<div class="add" style="color: #006e28">

<ul>
<li>If <em>S</em> contains <em>a</em>, the result is a pointer to
<em>a</em>.</li>
<li>Otherwise, the result is a member of <em>S</em> whose complete
object is not a synthesized object representation if any such result
would give the program defined behavior. If there are multiple possible
results that would give the program defined behavior, the result is an
unspecified choice among them.</li>
<li>Otherwise (i.e. when there are no such members of <em>S</em> that
would give the program defined behavior), if <em>a</em>’s object
representation is an array <em>A</em> and
<code class="sourceCode default">T</code> is similar to the type of
<em>A</em>, the result is a pointer to <em>A</em>.</li>
<li>Otherwise, if <em>a</em>’s object representation is an array
<em>A</em> and <code class="sourceCode default">T</code> is <em>cv</em>
<code class="sourceCode default">unsigned char</code>, the result is a
pointer to the first element of <em>a</em>’s object representation.</li>
<li>Otherwise, if <code class="sourceCode default">T</code> is
<em>cv</em> <code class="sourceCode default">std::byte</code> or
<em>cv</em> array of <code class="sourceCode default">std::byte</code>,
let <code class="sourceCode default">U</code> be the type obtained from
<code class="sourceCode default">T</code> by replacing
<code class="sourceCode default">std::byte</code> with
<code class="sourceCode default">unsigned char</code>. If a
<code class="sourceCode default">static_cast</code> of the operand to
<code class="sourceCode default">U*</code> would be well-formed and
would yield a pointer to an object representation or element thereof,
the result of the cast to <code class="sourceCode default">T*</code> is
that pointer value.</li>
<li>Otherwise, the result is a pointer to <em>a</em>.</li>
</ul>
<p>Otherwise, if the original pointer value points past the end of an
object <em>a</em>:</p>
<ul>
<li>If <em>a</em>’s object representation is an array <em>A</em> and
<code class="sourceCode default">T</code> is similar to the type of
<em>A</em>, the result is
<code class="sourceCode default">&amp;A + 1</code>.</li>
<li>Otherwise, if <em>a</em>’s object representation is an array
<em>A</em> and <code class="sourceCode default">T</code> is <em>cv</em>
<code class="sourceCode default">unsigned char</code>, the result is a
pointer past the last element of <em>A</em>.</li>
<li>Otherwise, if <code class="sourceCode default">T</code> is
<em>cv</em> <code class="sourceCode default">std::byte</code> or
<em>cv</em> array of <code class="sourceCode default">std::byte</code>,
let <code class="sourceCode default">U</code> be the type obtained from
<code class="sourceCode default">T</code> by replacing
<code class="sourceCode default">std::byte</code> with
<code class="sourceCode default">unsigned char</code>. If a
<code class="sourceCode default">static_cast</code> of the operand to
<code class="sourceCode default">U*</code> would be well-formed and
would yield a pointer value defined by one of the above cases, the
result of the cast to <code class="sourceCode default">T*</code> is that
pointer value.</li>
<li>Otherwise, the result is the value of the operand.</li>
</ul>

</div>
</blockquote>
<p><em>Drafting note:</em> The case of multiple objects is a
pre-existing defect: when a union has multiple members of type similar
to <code class="sourceCode cpp">T</code>, a
<code class="sourceCode cpp"><span class="kw">static_cast</span></code>
from <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code>
to <code class="sourceCode cpp">T<span class="op">*</span></code> can
yield a pointer to any of them. In cases that are allowed during
constant evaluation, the above change ensures that there is no ambiguity
about the result (<em>i.e.</em> the result always points to the original
object). At runtime, the choice is unobservable except when some choices
would result in lifetime-related UB, modifying a const object, or
accessing a volatile object through a non-volatile glvalue.</p>
<p>Modify §<span>7.6.6
<a href="https://wg21.link/N4988#expr.add">[expr.add]</a></span>p6 as
follows:</p>
<blockquote>
<p>For addition or subtraction, if the expressions
<code class="sourceCode cpp">P</code> or
<code class="sourceCode cpp">Q</code> have type “pointer to <em>cv</em>
<code class="sourceCode cpp">T</code>”<span class="rm" style="color: #bf0303"><del>, where
<span><code class="sourceCode default">T</code></span> and the array
element type are not similar, the behavior is
undefined.</del></span><span class="add" style="color: #006e28"><ins>,
one of the following shall hold:</ins></span></p>
<ul>
<li><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">T</code></span>
is similar to the array element type, or</ins></span></li>
<li><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">T</code></span>
is similar to <span><code class="sourceCode default">char</code></span>
or <span><code class="sourceCode default">std::byte</code></span> and
the pointer value points to a (possibly-hypothetical) element of an
object representation.</ins></span></li>
</ul>
<p><span class="add" style="color: #006e28"><ins>Otherwise, the behavior
is undefined.</ins></span></p>
</blockquote>
<p>Modify §<span>17.6.5
<a href="https://wg21.link/N4988#ptr.launder">[ptr.launder]</a></span>p3
as follows:</p>
<blockquote>
<p><em>Returns:</em> A value of type
<code class="sourceCode cpp">T<span class="op">*</span></code> that
points to <span class="add" style="color: #006e28"><ins>the
object</ins></span> <em>X</em> <span class="add" style="color: #006e28"><ins>that would give the program defined
behavior. If no such object exists, the behavior is
undefined</ins></span>.</p>
</blockquote>
<h1 data-number="9" id="known-issues"><span class="header-section-number">9</span> Known issues<a href="#known-issues" class="self-link"></a></h1>
<p>There are a number of known issues with the proposed wording that
need to be resolved before this paper can make any further progress:</p>
<ul>
<li>In [ptr.launder], there might be multiple such objects that would
give the program defined behaviour. We don’t know how to specify which
one is returned.</li>
</ul>
<h1 data-number="10" id="document-history"><span class="header-section-number">10</span> Document history<a href="#document-history" class="self-link"></a></h1>
<ul>
<li><strong>R0</strong>, 2019-07-30: Initial version.</li>
<li><strong>R1</strong>, 2019-09-28: Allowed pointer arithmetic on
expressions of type <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span><span class="op">*</span></code>,
<code class="sourceCode cpp"><span class="dt">char</span><span class="op">*</span></code>
and <code class="sourceCode cpp">std<span class="op">::</span>byte<span class="op">*</span></code>
when pointing to objects of different type. Removed exclusion of the
object representation of objects of zero size from appearing in the
object representation of their containing object. Added
multi-dimensional arrays of contiguous-layout types to the definition of
contiguous-layout types. Slight change to the behavior of
<code class="sourceCode cpp">std<span class="op">::</span>launder</code>
for when there are multiple viable objects.</li>
<li><strong>R2</strong>, 2019-11-20: Removed contiguous-layout types
from wording, this should be tackled by <span class="citation" data-cites="P1945R0">[<a href="https://wg21.link/p1945r0" role="doc-biblioref">P1945R0</a>]</span>.</li>
<li><strong>R3</strong>, 2022-02-15: Moved wording for casts to the
rules of pointer-interconvertibility. Changed the wording for
<code class="sourceCode cpp">std<span class="op">::</span>launder</code>
to bind to the best candidate object.</li>
<li><strong>R4</strong>, 2022-03-16: Changed the wording to fix
ambiguous usage of <em>N</em> in object representations
specification.</li>
<li><strong>R5</strong>, 2022-06-16: Reduced scope of paper to only
reading object representations, not writing. Completely rewrote
rationale. Added wording to prevent implicit object creation within
object representations. Added cross-reference to types with contiguous
storage ([intro.object]) in the wording. Fixed inconsistency in the
wording by defining that only <code class="sourceCode cpp"><span class="dt">unsigned</span>   <span class="dt">char</span></code>
is its own object representation, not
<code class="sourceCode cpp"><span class="dt">char</span></code> or
<code class="sourceCode cpp">std<span class="op">::</span>byte</code>.
Removed erroneous wording regarding memory locations. Added list of
known issues.</li>
<li><strong>R6</strong>, 2024-09-26: Converted to HTML (generated from
Markdown). Rebased wording on N4988. Removed unnecessary speculation
about the behaviour of modifying object representations. Made elements
of a subobject object representation distinct objects from the elements
of the containing object’s object representation and adjusted wording
accordingly. Clarified which bits of object representations are
indeterminate or erroneous. Removed some ambiguity over the result of
<code class="sourceCode cpp"><span class="kw">reinterpret_cast</span></code>
and added wording for the case of past-the-end pointers and casts to
<code class="sourceCode cpp">std<span class="op">::</span>byte<span class="op">*</span></code>.
Made the object representation of a non-contiguous object no longer
consist of <em>cv</em> <code class="sourceCode cpp"><span class="dt">unsigned</span>   <span class="dt">char</span></code>
objects. Defined object representation of (some) subobjects. Fixed a
wording bug for pointer arithmetic.</li>
</ul>
<h1 data-number="11" id="acknowledgements"><span class="header-section-number">11</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Many thanks to Jens Maurer and Hubert Tong for their help with the
wording. Thanks to Jason Cobb, John Iacino, Marcell Kiss, Killian Long,
Theodoric Stier, and everyone who participated on the std-proposals
mailing list and Core reflector for their countless reviews and
suggestions for earlier revisions of this paper. Thanks to Professor Ben
Woodard for his grammatical review of an earlier revision of this
paper.</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" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-CWG1314" class="csl-entry" role="doc-biblioentry">
[CWG1314] Nikolay Ivchenkov. 2011-05-06. Pointer arithmetic within
standard-layout objects. <a href="https://wg21.link/cwg1314"><div class="csl-block">https://wg21.link/cwg1314</div></a>
</div>
<div id="ref-CWG2901" class="csl-entry" role="doc-biblioentry">
[CWG2901] Jan Schultke. 2024-06-14. Unclear semantics for near-match
aliased access. <a href="https://wg21.link/cwg2901"><div class="csl-block">https://wg21.link/cwg2901</div></a>
</div>
<div id="ref-CWG43" class="csl-entry" role="doc-biblioentry">
[CWG43] Nathan Myers. 1998-09-15. Copying base classes (PODs) using
memcpy. <a href="https://wg21.link/cwg43"><div class="csl-block">https://wg21.link/cwg43</div></a>
</div>
<div id="ref-N4988" class="csl-entry" role="doc-biblioentry">
[N4988] Thomas Köppe. 2024-08-05. Working Draft, Programming Languages —
C++. <a href="https://wg21.link/n4988"><div class="csl-block">https://wg21.link/n4988</div></a>
</div>
<div id="ref-P0137R1" class="csl-entry" role="doc-biblioentry">
[P0137R1] Richard Smith. 2016-06-23. Core Issue 1776: Replacement of
class objects containing reference members. <a href="https://wg21.link/p0137r1"><div class="csl-block">https://wg21.link/p0137r1</div></a>
</div>
<div id="ref-P0593R6" class="csl-entry" role="doc-biblioentry">
[P0593R6] Richard Smith, Ville Voutilainen. 2020-02-14. Implicit
creation of objects for low-level object manipulation. <a href="https://wg21.link/p0593r6"><div class="csl-block">https://wg21.link/p0593r6</div></a>
</div>
<div id="ref-P1945R0" class="csl-entry" role="doc-biblioentry">
[P1945R0] Krystian Stasiowski. 2019-10-28. Making More Objects
Contiguous. <a href="https://wg21.link/p1945r0"><div class="csl-block">https://wg21.link/p1945r0</div></a>
</div>
</div>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Since C++20, one can also use <code class="sourceCode cpp">std<span class="op">::</span>bit_cast</code> to
copy the bytes into a struct that contains an array of <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>,
assuming that the struct does not have any padding.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>All citations to the Standard are to working draft N4988
unless otherwise specified.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>These reachability-based restrictions limit
compatibility between C and C++, in particular when it comes to C code
that uses <code class="sourceCode cpp">offsetof</code> to implement
intrusive data structures. A separate paper is being prepared that
proposes to remove these restrictions. Additional specification
difficulties are raised by such a direction, which will not be discussed
here.<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
