Почему sizeof ссылочного типа дает вам размер этого типа?

Согласно стандарту, в [expr.sizeof] (5.3.3.2) получаем:

При применении к эталонному или ссылочному типу, результатом является размер ссылочного типа.

Это, похоже, согласуется с тем, что ссылки не указаны [dcl.ref] (8.3.2.4):

Не указано, нужна ли ссылка для хранения

Но мне кажется довольно странным иметь такую ​​несогласованность внутри языка. Независимо от того, требует ли ссылка для хранения, не важно ли было бы определить, какой размер использует эта ссылка? Увидеть эти результаты просто не так:

sizeof(vector<int>) == 24
sizeof(vector<int>*) == 8
sizeof(vector<int>&) == 24
sizeof(reference_wrapper<vector<int>>) == 8

Какова причина отсутствия sizeof(T&) == sizeof(T) по определению?

Ответ 1

Выбор несколько произволен, и попытка полностью оправдать любой вариант приведет к циркулярным метафизическим аргументам.

Цель ссылки - быть (псевдоним для) самого объекта; под этим рассуждением имеет смысл иметь одинаковый размер (и адрес), и именно это указывает язык.

Абстракция негерметична - иногда ссылка имеет собственное хранилище, отдельно от объекта, что приводит к аномалиям, подобным тем, которые вы указываете. Но у нас есть указатели на то, когда нам нужно иметь дело с "ссылкой" как отдельной сущностью к объекту.

Ответ 2

Аргумент 1: Ссылка должна быть синонимом вашего объекта, поэтому интерфейс ссылки должен быть точно таким же, как интерфейс объекта, также все операторы должны работать одинаково на объекта и ссылки (кроме операторов типов).

Это будет иметь смысл в следующем коде:

MyClass a;
MyClass& b = a;
char a_buf[sizeof(a)];
char b_buf[sizeof(b)]; // you want b_buf be the same size as a_buf
memcpy(&a, a_buf, sizeof(a));
memcpy(&b, b_buf, sizeof(b)); // you want this line to work like the above line

Аргумент 2: С стандартной точки зрения С++ ссылки - это что-то под капотом, и он даже не говорит, занимают ли они память или нет, поэтому он не может сказать, как получить свой размер.

Как получить ссылочный размер:. Поскольку все ссылки на компиляторы реализуются с помощью постоянных указателей и они занимают память, есть способ узнать их размер.

class A_ref
{A& ref;}
sizeof(A_ref);

Ответ 3

Не особенно важно знать, сколько хранилищ требует эта ссылка, только изменение требований к хранилищу, вызванное добавлением ссылки. И вы можете определить:

struct with
{
    char c;
    T& ref;
};

struct without
{
    char c;
};

return sizeof (with) - sizeof (without);