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