C ++: Почему ссылка на выделенный объект стека обрабатывается так же, как ссылка на выделенный объект кучи? - PullRequest
1 голос
/ 28 февраля 2020

Первый вопрос по StackOverflow, поэтому будьте снисходительны, и не стесняйтесь, дайте мне обратную связь о том, как я мог бы лучше задать предстоящий вопрос. Спасибо!

Мне было интересно,

Я знаю, что ссылка на объекты, расположенные в стеке, не занимает места в памяти и не требует дополнительных затрат во время exe c, то есть:

int x;
x = 0;

и

int x;
int& y = x;
y = 0;

Должны быть точно идентичными при компиляции. Это звучит для меня очевидно, так как адрес b известен во время компиляции (потому что он такой же, как a, который известен во время компиляции)

Однако я не знаю, как компилятор C ++ справляется с этим, если адрес не известен во время компиляции, что происходит (насколько я знаю), когда объект, на который ссылаются, размещается в куче, то есть:

A& x = *new A();

Значение & x в этом контексте должно быть хранится где-то в скомпилированном коде, что приводит к другому поведению, чем если бы у вас была ссылка на объект, выделенный в стеке, верно?

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

Но почему нельзя изменить адрес ссылки на выделенный объект кучи (поскольку это должно быть значение l насколько я понимаю, из-за невозможности узнать это во время компиляции)? Почему у нас есть только тип «ссылка», а не «ссылка на объект, выделенный стеком» + «ссылка на объекты, выделенные кучей», поскольку они явно не обрабатываются одинаково в реализации?

Спасибо за ваши идеи!

Ответы [ 3 ]

1 голос
/ 28 февраля 2020

Значение &x в этом контексте должно храниться где-то в скомпилированном коде, что приводит к другому поведению, чем если бы у вас была ссылка на объект, выделенный в стеке, верно?

Как ссылки работают под капотом, зависит от реализации. Каждый компилятор может заставить их работать так, как они хотят. Но обычно самым простым решением является обработка T& как T * const, который никогда не может быть nullptr и чей адрес никогда не может быть получен. В тех случаях, когда упомянутый объект известен во время компиляции, тогда ссылку можно оптимизировать, и она, как никогда, не существовала. Но это также верно для указателей. Просто дополнительное свойство отсутствия адресации упрощает оптимизацию ссылок.

В чем вы можете быть уверены, так это в том, что поведение не будет отличаться в зависимости от того, как указанный объект был создан (динамически или как локальный объект). Да, случаи, которые вы показываете, могут привести к тому, что компилятор будет делать разные вещи, но поведение кода не является свойством того, что делает компилятор. Это рассуждение задом наперед. Код определяет строгое поведение в соответствии со стандартом языка. Все, что делает компилятор, должно оставить это поведение нетронутым, поскольку оно соблюдает то, что говорится в стандарте. Таким образом, ссылки имеют поведение, и некоторые варианты использования поведения будут инициировать создание разных сборок, но этот результат будет вести себя одинаково.

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

Но почему нельзя изменить адрес ссылки на выделенный объект кучи (поскольку это должно быть значение l до я понимаю, из-за невозможности узнать это во время компиляции)?

Причина, по которой вы не можете изменить то, на что ссылается ссылка, не является технической. По своей сути вы не хотите изменять то, к чему это относится, даже если бы эту функцию было легко реализовать. Это потому, что неизменный характер ссылок считается преимуществом. Если вам нужна ссылка, которая гарантированно содержит адрес и которую вы можете изменить для ссылки на другие вещи, язык уже содержит указатели, которые могут сделать это для вас.

Почему у нас есть только «ссылочный» тип, а не «ссылка на выделенный объект стека» + «ссылка на выделенные объекты кучи», поскольку в реализации они явно не обрабатываются одинаково?

Опять же, это не потому, что Реализация обрабатывает различные варианты использования функции, которая должна раскрывать интерфейс для разработчиков. Если вы пишете void mutate(int &) функцию, вы хотите обрабатывать все int с одинаковым образом, независимо от того, как они были созданы или какие оптимизации мог бы предложить компилятор. На самом деле не существует варианта использования функции, которая работает только с объектами, выделенными из стека.

0 голосов
/ 28 февраля 2020
A& x = *new A();

Как это работает?

new Оператор динамически выделяет память из heap, после чего вы присвоили ей ссылку на x.

int x;
int& y = x;
y = 0;

Здесь ссылка int x сохраняется в y во время компиляции, поскольку int x уже создан, тогда как объект x (A& x = *new A();) инициализируется во время выполнения. ,

Почему ссылка на выделенный объект стека обрабатывается так же, как ссылка на выделенный объект кучи?

Нет, это не так. Как только вы выделите память в heap, она будет там до тех пор, пока программа не завершится, или вы не вручную delete ее, тогда как объекты / переменные, выделенные в stack/locally, очищаются всякий раз, когда стековый фрейм этой функции / области видимости уничтожены, как и ссылки.

Подробнее об изменении / повторном назначении ссылок: Как переустановить ссылку, чтобы она ссылалась на другой объект?

0 голосов
/ 28 февраля 2020

Инициализации не должны иметь , которые должны быть выполнены во время компиляции, компилятор может генерировать код для их выполнения во время выполнения (если правая часть не известна или может быть вычислена во время компиляции).

Это то, что происходит, когда вы делаете

A& x = *new A;

Результат new A не известен во время компиляции, поэтому компилятор сгенерирует код, который вместо этого выполняет инициализацию x во время выполнения.

Это на самом деле не отличается от других инициализаций переменных во время компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...