Адрес x в функции void f(int&& x)
От: Максим Рогожин Россия  
Дата: 24.10.18 17:59
Оценка:
Привет!

Является ли данный код корректным?
void f(int&& x) {
    std::cout << &x << std::endl;
}

int main() {
   f(2+2);
   return 0;
}
Re: Адрес x в функции void f(int&& x)
От: σ  
Дата: 24.10.18 18:04
Оценка: :))
> Является ли данный код корректным?
Нет. std::cout и std::endl не определены.
Отредактировано 24.10.2018 18:28 σ . Предыдущая версия . Еще …
Отредактировано 24.10.2018 18:25 σ . Предыдущая версия .
Re[2]: Адрес x в функции void f(int&& x)
От: Максим Рогожин Россия  
Дата: 24.10.18 18:51
Оценка:
Здравствуйте, σ, Вы писали:

>> Является ли данный код корректным?

σ>Нет. std::cout и std::endl не определены.
Остальное все корректно?
Re[2]: Адрес x в функции void f(int&& x)
От: Максим Рогожин Россия  
Дата: 24.10.18 18:54
Оценка:
Здравствуйте, σ, Вы писали:

>> Является ли данный код корректным?

σ>Нет. std::cout и std::endl не определены.
А с чего вы взяли что они не определены? Стандартом требуется что бы были заголовочные файлы для std::cout и std::endl?
Re: Адрес x в функции void f(int&& x)
От: wander  
Дата: 24.10.18 20:50
Оценка: +3
Здравствуйте, Максим Рогожин, Вы писали:

МР>Привет!


МР>Является ли данный код корректным?

МР>
МР>void f(int&& x) {
МР>    std::cout << &x << std::endl;
МР>}

МР>int main() {
МР>   f(2+2);
МР>   return 0;
МР>}
МР>


Если не заниматься буквоедством по поводу отсутствующего #include <iostream>, то да — код корректный.
Re: Адрес x в функции void f(int&& x)
От: rg45 СССР  
Дата: 25.10.18 10:58
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Является ли данный код корректным?

МР>
МР>void f(int&& x) {
МР>    std::cout << &x << std::endl;
МР>}
МР>


Да, является корректным. Потому, что x — это lvalue. Вообще, следует запомнить одно простое правило: как только rvalue объект приобретает имя, он превращается в lvalue. А чтобы обращаться с ним как с rvalue, следует применять std::forward или std::move.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Адрес x в функции void f(int&& x)
От: Максим Рогожин Россия  
Дата: 25.10.18 15:15
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Максим Рогожин, Вы писали:


МР>>Является ли данный код корректным?

МР>>
МР>>void f(int&& x) {
МР>>    std::cout << &x << std::endl;
МР>>}
МР>>


R>Да, является корректным. Потому, что x — это lvalue. Вообще, следует запомнить одно простое правило: как только rvalue объект приобретает имя, он превращается в lvalue. А чтобы обращаться с ним как с rvalue, следует применять std::forward или std::move.


void f(int&& x) {
    std::cout << &x << std::endl;
}

void g(int& x) {
    std::cout << &x << std::endl;
}

int h();

int main() {
   f(h());
   int local_x = 1024;
   g(x);
   return 0;
}


В обоих случаях, x это переменная на стеке, т.е. lvalue. Но,

в случае g(int& x):

x это другое имя для local_x: &x == &local_x

а в случае f(int&& x):

x это, наверное, тоже имя для временного объекта: &x == временного объекта?

А если временный объект не имеет адреса, а возвращается из функции h() через регистр процессора? Как его адрес взять?
Re[3]: Адрес x в функции void f(int&& x)
От: zaufi Земля  
Дата: 25.10.18 19:50
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Здравствуйте, σ, Вы писали:


>>> Является ли данный код корректным?

σ>>Нет. std::cout и std::endl не определены.
МР>А с чего вы взяли что они не определены? Стандартом требуется что бы были заголовочные файлы для std::cout и std::endl?

обратить внимание на defined in header... иначе да -- нет header'a -- не будет определения %)

странно что такой вопрос вообще возник... как ты себе представляешь, чтобы какие-то сущности появлялись "из ниоткуда"... это же не JS какой-нибудь %)
здесь максимум предопределено несколько макросов (ну чуть больше после С++14/17) и на вскидку вспоминается еще результат `typeid`, но чтобы с ним работать адекватно также нужно подключить `typeinfo` header.
Re[3]: Адрес x в функции void f(int&& x)
От: zaufi Земля  
Дата: 25.10.18 20:51
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>void f(int&& x) {
МР>    std::cout << &x << std::endl;
МР>}

МР>void g(int& x) {
МР>    std::cout << &x << std::endl;
МР>}

МР>int h();

МР>int main() {
МР>   f(h());
МР>   int local_x = 1024;
МР>   g(x);
        ^
        `local_x` наверное всеже...
МР>   return 0;
МР>}


может понимание того, в какой машинный код обычно компилится С\С++ поможет разобраться...

МР>В обоих случаях, x это переменная на стеке, т.е. lvalue. Но,


Переменная "на стэке" (т.е. в памяти) уже само по себе означает что у нее есть адрес -- т.е. с точки зрения C/C++ его можно "взять".
Даже если это параметр функции (которые по соглашению передаются через стэк), внутри вызванной функции у него будет адрес (и да, его можно "взять", какого бы типа он там ни был в С/С++). Если компилятор хотел было оптимизировать эту функцию (допустим она не экспортируемая) и передавать в нее параметр через регистр, но оказалось, что внутри "кто-то берет адрес у параметра", то компилятор сделает так, чтобы это было осуществимо... т.е. просто не станет оптимизировать передачу этого параметра %)

"временные" (или более обще rvalue) объекты в С/С++, на уровне машинных команд это

* например значения возвращаемые через регистры
* результаты "подвыражений" (например `foo(some + other)`) -- тоже как правило компилятор хранит в регистрах до момента использования, который как правило наступает где-то "рядом"
* или например т.н. непосредственные операнды (инструкций) -- литералы к примеру как в `bar += 100500;` вот это вот `100500` будет лежать непосредственно в сегменте кода, а не данных...

т.е. в целом любая сущность не в памяти предназначенной для хранения данных (имеется ввиду сегменты `.data`, `.const`, `.bss` & etc, но не `.text`).
Сущности же, которые тем или иным образом попадают в `.data`, by design имеют адрес, который можно "взять" в С/С++ -- таким образом в этих языках они получаются `lvalue` тем или иным образом.

Возмем `f(h())` в твоем примере. Результат `h()` вероятнее всего просто "перекочует" из регистра (где по соглашению `h()` его должен будет вернуть) сразу в стэк как параметр для `f()`. Если ты "сохранишь" этот "промежуточный" результат в "переменную", компилятор вероятнее всего, даже не будет для нее выделять место в стэке, если единственное использование такой переменной это тутже быть переданной в `f(tmp)`. Но как только ты возмешь адрес у этой переменной, компилятор будет вынужден/обязан "дать" ей место в стэке (для автоматических переменных). Просто потому, что у нее должен быть адрес %) И в этот момент в С\С++ она перестает быть `rvalue` и становится `lvalue` %)

С точки зрения машинных команд: все, что находится в памяти (RAM), безусловно имеет адрес. Просто в С/С++ этот факт (абстракция "память") "перекочевал" с некоторыми ограничениями в виде разделения r/x/l values %) -- мол не у всего можно взять адрес... С одной стороны это "развязывает компилятору руки" для оптимизаций, с другой, в целом то не все эти аппаратные фичи нужны программисту...
Re[4]: Адрес x в функции void f(int&& x)
От: Максим Рогожин Россия  
Дата: 25.10.18 21:03
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>обратить внимание на defined in header... иначе да -- нет header'a -- не будет определения %)


Z>странно что такой вопрос вообще возник... как ты себе представляешь, чтобы какие-то сущности появлялись "из ниоткуда"... это же не JS какой-нибудь %)

Z>здесь максимум предопределено несколько макросов (ну чуть больше после С++14/17) и на вскидку вспоминается еще результат `typeid`, но чтобы с ним работать адекватно также нужно подключить `typeinfo` header.

Ну и что, а может у меня экзотическая реализация компилятора — этот header в самом компиляторе захардкоден — это что не соответствовало бы стандарту?
Re[5]: Адрес x в функции void f(int&& x)
От: zaufi Земля  
Дата: 25.10.18 21:57
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Здравствуйте, zaufi, Вы писали:


Z>>обратить внимание на defined in header... иначе да -- нет header'a -- не будет определения %)


Z>>странно что такой вопрос вообще возник... как ты себе представляешь, чтобы какие-то сущности появлялись "из ниоткуда"... это же не JS какой-нибудь %)

Z>>здесь максимум предопределено несколько макросов (ну чуть больше после С++14/17) и на вскидку вспоминается еще результат `typeid`, но чтобы с ним работать адекватно также нужно подключить `typeinfo` header.

МР>Ну и что, а может у меня экзотическая реализация компилятора — этот header в самом компиляторе захардкоден — это что не соответствовало бы стандарту?


попытка использовать нечто, чего не было явно объявлено это не валидная программа с точки зрения стандарта -- и если твой компилятор не делает ее невалидной, то он сам становится невалидным %)
Re[4]: Адрес x в функции void f(int&& x)
От: σ  
Дата: 26.10.18 01:22
Оценка:
> rvalue) объекты
Ничего, что rvalue — это выражения?
Re[5]: Адрес x в функции void f(int&& x)
От: rg45 СССР  
Дата: 26.10.18 08:05
Оценка: +1
Здравствуйте, σ, Вы писали:

>> rvalue) объекты

σ>Ничего, что rvalue — это выражения?

Почему бы тебе просто не рассказать, как правильно? Иы бы все оценили. А то ведь искать неточности в высказываниях других всегда легче, чем отвечать на вопросы.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Адрес x в функции void f(int&& x)
От: rg45 СССР  
Дата: 26.10.18 08:27
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:


МР>В обоих случаях, x это переменная на стеке, т.е. lvalue. Но,

МР>в случае g(int& x):
МР>x это другое имя для local_x: &x == &local_x
МР>а в случае f(int&& x):
МР>x это, наверное, тоже имя для временного объекта: &x == временного объекта?
МР>А если временный объект не имеет адреса, а возвращается из функции h() через регистр процессора? Как его адрес взять?

Смотри, есть спецификация языка, и есть требования к поведению программы. В данном случае они таковы, что долдно быть возможным получить адреса фактических параметров этих фунций. Каким образом компилятор удовлетворит этим требованиям — это уже личное дело компилятора, точнее, его разработчиков. То ли он скопирует значение из регистра процессора в память, то ли сразу разместит это значение в памяти (RVO, NRVO), то ли еще как-то. Например, в данном конкретном случае, он может вообще никаких объектов нигде не ращмещать — поскольку, в программе сам объект не используется, а используется только его адрес.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Адрес x в функции void f(int&& x)
От: σ  
Дата: 26.10.18 12:08
Оценка:
R>rvalue объект

Не существует таких сущностей в C++
Re[3]: Адрес x в функции void f(int&& x)
От: rg45 СССР  
Дата: 26.10.18 12:40
Оценка:
Здравствуйте, σ, Вы писали:

R>>rvalue объект


σ>Не существует таких сущностей в C++


Тем не менее, термин "prvalue objects" можно встретиь в стандарте. Саттер, Мейерс и Александреску не стеняются пользоваться этим термином. И понять, что имеется в виду, вполне можно, если не ставить себе целью бессмысленное буквоедство.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 26.10.2018 12:59 rg45 . Предыдущая версия . Еще …
Отредактировано 26.10.2018 12:56 rg45 . Предыдущая версия .
Отредактировано 26.10.2018 12:56 rg45 . Предыдущая версия .
Re[4]: Адрес x в функции void f(int&& x)
От: N. I.  
Дата: 26.10.18 13:50
Оценка: 10 (1) +2
zaufi:

Z>Переменная "на стэке" (т.е. в памяти) уже само по себе означает что у нее есть адрес -- т.е. с точки зрения C/C++ его можно "взять".


Правила C++ применяются к адресам в воображаемой памяти абстрактной машины, которая представляет собой чисто умозрительную модель вычислений. Задача компилятора C++ — преобразовать исходную программу на C++ в программу, понятную среде исполнения и выдающую некие результаты, которые могли бы получиться при выполнении исходной программы на абстрактной машине, следуя описанным в стандарте правилам. От преобразованной программы не требуется, чтобы она работала с доступной ей памятью точно так же, как это делает абстрактная машина со своей воображаемой памятью. Таким образом, между адресами в рамках абстрактной машины и адресами, которые использует процессор, может не быть никакой связи.

Z>Даже если это параметр функции (которые по соглашению передаются через стэк), внутри вызванной функции у него будет адрес (и да, его можно "взять", какого бы типа он там ни был в С/С++). Если компилятор хотел было оптимизировать эту функцию (допустим она не экспортируемая) и передавать в нее параметр через регистр, но оказалось, что внутри "кто-то берет адрес у параметра", то компилятор сделает так, чтобы это было осуществимо... т.е. просто не станет оптимизировать передачу этого параметра %)


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

Z>"временные" (или более обще rvalue) объекты в С/С++, на уровне машинных команд это


Временные объекты в C++ — это абстракция ЯП высокого уровня, единственное предназначение которой — быть частью правил, определяющих observable behavior, ни больше ни меньше. Что там будет на уровне машинных команд, зависит от того, как компилятор захочет реализовать допустимое с точки зрения правил C++ observable behavior.

Z>Возмем `f(h())` в твоем примере. Результат `h()` вероятнее всего просто "перекочует" из регистра (где по соглашению `h()` его должен будет вернуть) сразу в стэк как параметр для `f()`.


Это всё гадание на кофейной гуще. Компилятор может встроить оба вызова, и тогда от соглашений по вызову функций ничего не зависит. А если и не встроит, передача аргумента тоже может быть сделана через регистр, как и возврат значения.

Z>Если ты "сохранишь" этот "промежуточный" результат в "переменную", компилятор вероятнее всего, даже не будет для нее выделять место в стэке, если единственное использование такой переменной это тутже быть переданной в `f(tmp)`. Но как только ты возмешь адрес у этой переменной, компилятор будет вынужден/обязан "дать" ей место в стэке (для автоматических переменных). Просто потому, что у нее должен быть адрес %)


Ещё раз: взятый у объекта C++ адрес — это всего лишь воображаемая абстракция, и компилятор вовсе не обязан резервировать какую-либо адресуемую память под воображаемые объекты с воображаемыми адресами. Проанализировав, как полученный адрес используется в дальнейшем, компилятор в некоторых случаях может изменить алгоритм так, что адресуемая память для получения требуемого правилами C++ результата работы программы не понадобится.
Re[4]: Адрес x в функции void f(int&& x)
От: σ  
Дата: 26.10.18 13:52
Оценка:
R>>>rvalue объект

σ>>Не существует таких сущностей в C++


R>Тем не менее, термин "prvalue objects" можно встретиь в стандарте.


Это не термин. Это словосочетание. Которое можно встретить всего 1 раз. В non-normative сноске.
И это не повод так выражаться, это повод закинуть editorial issue: https://github.com/cplusplus/draft/issues

R> Саттер, Мейерс и Александреску не стеняются пользоваться этим термином.


А если бы они не стеснялись головой в унитаз макаться — ты бы тоже макался?
Отредактировано 26.10.2018 14:03 σ . Предыдущая версия .
Re[5]: Адрес x в функции void f(int&& x)
От: rg45 СССР  
Дата: 26.10.18 14:29
Оценка:
Здравствуйте, σ, Вы писали:


σ>Это не термин. Это словосочетание. Которое можно встретить всего 1 раз. В non-normative сноске.


Ну вот и у меня тоже словосочетание.

σ>А если бы они не стеснялись головой в унитаз макаться — ты бы тоже макался?


Если бы у бабушки была борода, она была бы дедушкой.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Адрес x в функции void f(int&& x)
От: σ  
Дата: 26.10.18 14:34
Оценка:
σ>>А если бы они не стеснялись головой в унитаз макаться — ты бы тоже макался?

R>Если бы у бабушки была борода, она была бы дедушкой.


Бывают различные гормональные расстройства, при которых у женщин начинает расти заметная борода. Дедушками подобные бабушки не становятся.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.