C ++标准的当前草案(2019年3月)具有以下段落([basic.types] p.4)(强调我的意思):
类型T的对象的对象表示形式是类型T的对象占用的N个无符号字符对象的序列,其中N等于sizeof(T)。 类型T的对象的值表示形式是参与表示类型T的值的位的集合。 对象表示形式中不属于值表示形式的位是填充位。 对于普通可复制类型,值表示形式是对象表示形式中确定值的一组位,值是实现定义的一组值中的一个离散元素。
为什么突出显示的句子仅限于可复制的类型?是因为不可平凡对象的值表示形式中的某些位可能不在其对象表示形式中? This answer和this one都暗示了这一点。
但是,在上面链接的答案中,对象的概念性值是基于用户引入的语义的。在第一个链接的答案的示例中:
class some_other_type
{
int a;
std::string s;
};
用户确定类型some_other_type
的对象的 value 包括属于字符串s
的字符。
我试图考虑一些示例,其中某个对象的某些位(不是不可复制的)值表示在其对象表示之外< / em>是隐式的(实现必须执行,它不是由用户任意决定的。)
我想到的一个例子是,带有虚拟方法的基类子对象的值表示形式可能包含完整对象的 object表示形式中的位它所属的对象是因为基类子对象的行为与其将是完整对象本身的情况相比,可能会有所不同(可能具有“不同的值”)。
我想到的另一个例子是, vtable 也可能是其 vtable指针的对象的值表示的一部分。指向它。
这些例子正确吗?还有其他例子吗?
标准委员会引入的突出显示的句子是由于以下事实:对象的语义“值”可以由用户确定(如在两个链接的答案中一样),或者是由于实现方式可以确定(或可能被迫)执行此操作,或者两者都执行?
谢谢。
答案 0 :(得分:6)
在我的解释中,您突出显示的句子的重点是这一部分:
对于普通可复制类型,值表示形式是对象表示形式中的一组位,用于确定一个值,该值是实现定义的一组值中的一个离散元素。
实质上,该标准的[basic.types]#4表示“每个对象都有一组位O
作为其对象表示形式,还有一组位其值表示V
。集合P = O without V
是填充位。对于普通可复制类型,V
是O
”的子集。后者很重要,因为这意味着对于平凡可复制的类型,在O
位位周围进行复制也可以在V
附近安全地进行复制,从而保留了该值。此处无需为其他类型定义V
的方式(如果需要,可以将其设置为整个抽象机)。
要回答评论中提出的修订问题:
为什么一个实现不能说出1110000100010001111是非平凡对象的对象表示是什么意思?是因为有其他一些位(在此对象表示形式之外)有助于确定对象具有什么值?
我们以std::string
为例。它不可复制,因为它必须处理内存管理。
如果两个std::string
对象具有相同的位模式,它们是否意味着同一件事?
不。 at least one implementation通过使其缓冲区指针指向自身(gcc)来指示小型字符串优化。销毁后,当(且仅当)缓冲区未指向该确切位置时,才会释放该缓冲区。
很明显,在此实施例中,位于不同位置的两个std::string
对象必须使用不同位模式表示相同(小的)字符串值(缓冲区指针必须会有所不同)。而且更重要的是,两个对象中相同的位模式可能意味着截然不同的事物-在一种情况下可能表示SSO,而在另一种情况下则没有。
如您所见,这里每个std::string
的值表示形式都包含其他信息:它在内存中的位置(即this
的值)。该标准没有进一步规定以位表示的精确度。