Re: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 10.01.04 20:50
Оценка: 14 (1)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Статья:

ПК>Q&A: lvalue и rvalue

ПК>Авторы:

ПК> Павел Кузнецов

ПК>Аннотация:

ПК>lvalue и rvalue — что это такое.

Статья хорошая, но не полная. Надо было бы добавить следующее.

1) Существует принцип, сформулированный Страуструпом в своей книге. Если результат выражения может быть конституирован как lvalue, то это и есть lvalue.
Рассмотрим, например, следующую маленькую программу.

/* main.cpp */ 

/* main() */ 

#include <iostream> 

using namespace std;

int main()
 {
  int x=100;
  /*short*/ int y=20;
  
  ((x<y)?x:y)=1000;
  
  cout << "x=" << x << " y=" << y << endl ;
 
  return 0;
 }


Результат выражения ((x<y)?x:y) -- lvalue, как это ни странно с первого взгляда. А вот если снять комментарий, то компилятор обругает. Из этого вытекает одно не очевидное следствие -- будет ли результатом выражения (или подвыражения) lvalue нельзя определить на стадии синтаксического анализа программы (точнее говоря, не всегда возможно). Необходим анализ типов подвыражений, который осуществляется на фазе семантического анализа, когда генериться код, вычисляющий выражение. В более простых языках, это было возможно сделать на стадии синтаксического анализа.

2) Важное исключение из принципа 1) -- временные объекты, созданные явно или неявно (как результат неявной операции приведения типа или результат вызова функции) lvalue не являются, хотя ничто не мешало бы их конституировать в таком качестве. Объект есть, но не lvalue. Сделано это для предотвращения тонких ошибок-сюрпризов. В приведённом выше примере со снятым комментарием, если бы это было разрешено, произошло бы вот что. Переменная y была бы приведена к типу int, т.е. была бы создана временная переменная типа int со значением, полученным из y "продвижением".
Далее, поскольку это значение меньше, чем у х, именно эта временная переменная и была бы результатом вычисления выражения ((x<y)?x:y), этой переменной было бы присвоено значение 1000, после чего, эта переменная благополучно умирает, а y, естественно, остаётся без изменений. Киндерсюрприз.

3) Маленькое напоминание. Временные объекты не имеют имени. Это их характерная особенность. Поэтому определять lvalue или нет лучше всего спросив себя, есть ли имя, связанное с этой величиной или нет (надо ещё помнить про операцию разыменования указателя, и про ссылочные типы). Критерий возможности взятия адреса чисто теоретический. Можно ли у выражения ((x<y)?x:y) взять адрес? Непонятно. Если lvalue, то можно, а если нет то нельзя. Точное правило здесь такое. Если x и y оба lvalue и при приведении к общему типу не будет введено временных объектов, то и результат будет lvalue. Т.е. типы x и y не обязаны точно совпадать, но они должны быть достаточно близки. Например, x может быть типа int, а y -- типа int &. Аналогичные правила действуют и для других примитивных операций. Было бы хорошо добавить в статью summary на этот счёт.
Тем более, что большинство операций на самом деле всегда порождают rvalue, и только некоторые могут порождать lvalue.

4)

В частности, результат вызова функций, возвращающих объекты не по ссылке;

Укоренившееся неправильное выражение. Функция, на самом деле, возвращает ссылку на объект, а не объект по ссылке. С самим объектом ничего не происходит, он не возвращается функцией. Ссылка, будучи временным объектом, тем не менее, является lvalue, просто в силу своей природы. Ссылки -- особый объект в C++, они не представляют из себя новый объект, а лишь служат заместителем уже существующего объекта. Поэтому во многих правилах, в том числе и в определении lvalue/rvalue, они трактуются особым образом. Общая идея со ссылками в том, что их можно использовать везде, где можно использовать объект данног типа. Есть правда, возможность, используя специализацию шаблонов, различать эти случаи.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 10.01.04 21:38
Оценка: 5 (1)
Здравствуйте, Шахтер, Вы писали:

Ш>Статья хорошая, но не полная. Надо было бы добавить следующее.

Ш>1) Существует принцип, сформулированный Страуструпом в своей книге. Если результат выражения может быть конституирован как lvalue, то это и есть lvalue.

Гм... Может быть и стоит — надо подумать, что это даст в практическом смысле читателю... Но, вообще, на первый взгляд, мысль очень здравая.

Ш>временные объекты, созданные явно или неявно <...> lvalue не являются <...> Сделано это для предотвращения тонких ошибок-сюрпризов


К сожалению, эта "защита" не работает с класс-типами, т.к. для rvalue класс-типов можно вызывать неконстантные функции-члены, в частности, operator =.
#include <iostream> 

struct C
{
  C(int i) : i(i) { }

  int i;
};

bool operator <(const C& c, int i) { return c.i < i; }

std::ostream& operator <<(std::ostream& os, const C& c) { return os << c.i; }

int main()
{
  C x (100);
  int y = 20;
  ((x<y)?x:y)=1000;
  std::cout << "x=" << x << " y=" << y << std::endl;
}

x=100 y=20


Ш>определять lvalue или нет лучше всего спросив себя, есть ли имя, связанное с этой величиной или нет (надо ещё помнить про операцию разыменования указателя, и про ссылочные типы)


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

Ш>Критерий возможности взятия адреса чисто теоретический. Можно ли у выражения ((x<y)?x:y) взять адрес? Непонятно. Если lvalue, то можно, а если нет то нельзя.


Критерий наличия имени здесь применим еще в меньшей степени Критерий возможности применения встроенной операции взятия адреса, по крайней мере, позволяет определить, является ли выражение lvalue или rvalue путем компиляции.

Ш>Точное правило здесь такое. Если x и y оба lvalue и при приведении к общему типу не будет введено временных объектов, то и результат будет lvalue.


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

Ш>Например, x может быть типа int, а y -- типа int &.


При этом важно понимать, что на уровне анализа выражений типов int& уже не существует — есть lvalue типа int (5/6).

Ш>Аналогичные правила действуют и для других примитивных операций. Было бы хорошо добавить в статью summary на этот счёт.


Возможно, так и сделаем в следующей версии — по-моему, наличие подобной summary может оказаться полезным.

Ш>

Ш>В частности, результат вызова функций, возвращающих объекты не по ссылке;

Ш>Укоренившееся неправильное выражение. Функция, на самом деле, возвращает ссылку на объект, а не объект по ссылке. С самим объектом ничего не происходит, он не возвращается функцией.

Ну, имхо, это вопрос теологический

Ш>Ссылка, будучи временным объектом,


А вот это уже просто неверное утверждение: ссылка объектом не является.

Ш>тем не менее, является lvalue, просто в силу своей природы.


lvalue/rvalue является характеристикой выражений. Выражение же не может иметь тип "ссылка" (5/6). Но вот выражение, состоящее из имени переменной, тип которой "ссылка на X", действительно, является lvalue типа X.

Ш>Общая идея со ссылками в том, что их можно использовать везде, где можно использовать объект данног типа. Есть правда, возможность, используя специализацию шаблонов, различать эти случаи.


Например? Ты полагаешь, что с помощью шаблонов можно отличить, например, int& i от int j?
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 11.01.04 17:34
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Здравствуйте, Шахтер, Вы писали:


ПК>При этом важно понимать, что на уровне анализа выражений типов int& уже не существует — есть lvalue типа int (5/6).


Оба на. Не знал о существовании такого правила. Можно пояснить, в чем глубокий смысл такой автоматической конверсии типов?

Ш>>

Ш>>В частности, результат вызова функций, возвращающих объекты не по ссылке;

Ш>>Укоренившееся неправильное выражение. Функция, на самом деле, возвращает ссылку на объект, а не объект по ссылке. С самим объектом ничего не происходит, он не возвращается функцией.

ПК>Ну, имхо, это вопрос теологический


Ну почему теологический? В одном случае конструируется полноценный объект, в другом конструируется ссылка на объект, расположенный где-то ещё. Точно так же, как при декларациях.

int x=1;

int &y=x;


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

Ш>>Ссылка, будучи временным объектом,


ПК>А вот это уже просто неверное утверждение: ссылка объектом не является.


Это почему ещё не является? Это тоже записано в Стандарте? Где? Во всяком случае, ведёт она себя так же как обычный временный объект.

Процитирую на всякий случай Страуса.

The obvious implementation of a reference is as a (constant) pointer that is dereferenced each time it is used. It doesn’t do much harm thinking about references that way, as long as one remembers that a reference isn’t an object that can be manipulated the way a pointer is:

<картинка>

In some cases, the compiler can optimize away a reference so that there is no object representing that reference at runtime.


Ш>>тем не менее, является lvalue, просто в силу своей природы.


ПК>lvalue/rvalue является характеристикой выражений. Выражение же не может иметь тип "ссылка" (5/6). Но вот выражение, состоящее из имени переменной, тип которой "ссылка на X", действительно, является lvalue типа X.


Ш>>Общая идея со ссылками в том, что их можно использовать везде, где можно использовать объект данног типа. Есть правда, возможность, используя специализацию шаблонов, различать эти случаи.


ПК>Например? Ты полагаешь, что с помощью шаблонов можно отличить, например, int& i от int j?


Ну, в свете правила 5/6 это сделать нельзя и это плохо. Плскольку i и j -- сущности совершенно разной природы.
Есть правда такой примерчик (нечестный).

/* main.cpp */ 

/* main() */ 

#include <iostream> 
#include <typeinfo>

using namespace std;

template <class T>
struct IsReference
 {
  static const bool Value=false;
 };

template <class T>
struct IsReference<T &>
 {
  static const bool Value=true;
 };
 
template <class T> 
void test(T)
 {
  cout << "IsReference<T>::Value=" << IsReference<T>::Value << endl ;
 }
 
int main()
 {
  int x=0;
 
  test<int>(x);
  test<int &>(x);
 
  return 0;
 }


Тут возникает один интересный вопрос. Если в язык добавят оператор typeof, то получится такая несуразность при текущем положении дел.

template <class T> 
void test(T х)
 {
  cout << "IsReference<T>::Value=" << IsReference<T>::Value << endl ;
  
  cout << "IsReference<T>::Value=" << IsReference<typeof (x)>::Value << endl ;
 }


При T типа int & возникнет расхождение.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 11.01.04 21:43
Оценка: 14 (1)
Здравствуйте, Шахтер, Вы писали:

ПК>>При этом важно понимать, что на уровне анализа выражений типов int& уже не существует — есть lvalue типа int (5/6).


Ш>Оба на. Не знал о существовании такого правила. Можно пояснить, в чем глубокий смысл такой автоматической конверсии типов?


Чтобы не было тонких сюрпризов при переходе от "прямого" доступа к использованию ссылок и обратно.

ПК>>>>В частности, результат вызова функций, возвращающих объекты не по ссылке;


Ш>>>Укоренившееся неправильное выражение.


ПК>>Ну, имхо, это вопрос теологический


Ш>Ну почему теологический? В одном случае конструируется полноценный объект, в другом конструируется ссылка на объект, расположенный где-то ещё. Точно так же, как при декларациях.


Имхо, выражение "возвращать/передавать объект по ссылке/по значению" уже достаточно давно устоялось, чтобы не считать его правильным или неправильным. Если я не ошибаюсь, оно существовало раньше, чем ссылки появились в C++. Этого выражения не чураются и такие классики, как Страуструп или Ахо, Сети и Ульман... В общем, если оно и является "некошерным" в каких-то кругах, я все равно не сильно расстроюсь, пребывая в такой хорошей компании

ПК>>ссылка объектом не является.


Ш>Это почему ещё не является?


У ссылок нет основных атрибутов, присущих объектам: состояния и — что главное — identity (забыл как это по-русски).

Ш>Это тоже записано в Стандарте? Где?


В разных местах. Во-первых, четко видно, что стандарт разделяет объекты, функции и ссылки, никогда не смешивая одно с другим (1.3.9, 3.5 и т.п.). Во-вторых, определение объекта (1.8) говорит, что объект — область памяти; ссылка не обязательно имеет ассоциированную с ней область памяти. То же определение говорит, что объект имеет object type; п. 3.9/9 совершенно четко говорит, что ни функциональные, ни ссылочные типы не являются объектными. В-третьих, если бы ссылки являлись объектами, многие пункты стандарта утратили бы смысл или были бы противоречивыми (3.9/4 и т.п.). В общем, здесь скорее имеет смысл говорить о том, что стандарт нигде не подтверждает идею о том, что ссылки являются объектами.

Ш>Во всяком случае, ведёт она себя так же как обычный временный объект.


Объект, или значение? Например, int(10) объектом не является...

Ш>Процитирую на всякий случай Страуса.

Ш>

Ш>The obvious implementation of a reference is as a (constant) pointer that is dereferenced each time it is used. It doesn’t do much harm thinking about references that way, as long as one remembers that a reference isn’t an object that can be manipulated the way a pointer is: . . .
Ш>In some cases, the compiler can optimize away a reference so that there is no object representing that reference at runtime.


Все верно. Реализована ссылка может быть указателем, который является объектом; при этом объектом она не является. Можно еще процитировать оттуда же чуть ранее:

A reference is an alternative name for an object.


Т.е. ссылка не является объектом сама по себе, а лишь служит еще одним именем для некоторого объекта. Также имеет смысл посмотреть аналогичное стандартному, но чуть менее подробное и строгое определение объекта у Страуструпа (4.9.6).

Ш>Ну, в свете правила 5/6 это сделать нельзя и это плохо. Плскольку i и j -- сущности совершенно разной природы.

Ш>Есть правда такой примерчик (нечестный).
Ш>
Ш>. . .
Ш>

Гм... Что-то я не пойму, к чему этот пример: для ссылки он выведет то же самое. Или ты о том, что можно отличить явно указанный тип T& от T? Но, по-моему, это не относится к начальному утверждению: "Общая идея со ссылками в том, что их можно использовать везде, где можно использовать объект данног типа. Есть правда, возможность, используя специализацию шаблонов, различать эти случаи" (выделено мной).

Ш>Тут возникает один интересный вопрос. Если в язык добавят оператор typeof, то получится такая несуразность при текущем положении дел.

Ш>
Ш>. . .
Ш>

Ш>При T типа int & возникнет расхождение.

Вокруг typeof/decltype, вообще, много проблем (см., например, статью Страуструпа: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1527.pdf ); в настоящий момент обе известные мне реализации typeof (GCC, EDG) отбрасывают ссылку при выводе типа.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Q&A: lvalue и rvalue
От: Аноним  
Дата: 12.01.04 15:26
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

А>>в выражении ++i (которое l-value) будет иметь место l-value to r-value преобразование (т.е. тут ведь необходимо получить старое значение)?


ПК>Важно различать доступ к старому значению и lvalue-to-rvalue conversion.

[...]
ПК>Таким образом, если i имеет тип int, и если выражение ++i написано так, как выше, — т.е. его результат не используется в контексте, где требуется rvalue — то никакого преобразования к rvalue не произойдет.

Ммм... любопытно.

Правильно ли я понял?

int main()
{
    int i;

    ++i;        // well-defined behavior
    i = i + 1;  // undefined behavior
}
Re[4]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 12.01.04 18:14
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>int main()
А>{
А>    int i;

А>    ++i;        // well-defined behavior
А>    i = i + 1;  // undefined behavior
А>}
А>


Не уверен, что мы понимаем друг друга... Почему во втором случае должно быть неопределенное поведение?..
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[5]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 13.01.04 02:05
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Здравствуйте, Шахтер, Вы писали:


ПК>Имхо, выражение "возвращать/передавать объект по ссылке/по значению" уже достаточно давно устоялось, чтобы не считать его правильным или неправильным. Если я не ошибаюсь, оно существовало раньше, чем ссылки появились в C++. Этого выражения не чураются и такие классики, как Страуструп или Ахо, Сети и Ульман... В общем, если оно и является "некошерным" в каких-то кругах, я все равно не сильно расстроюсь, пребывая в такой хорошей компании


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

ПК>>>ссылка объектом не является.


Ш>>Это почему ещё не является?


ПК>У ссылок нет основных атрибутов, присущих объектам: состояния и — что главное — identity (забыл как это по-русски).


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

identity -- наверное идентичность? А у указателя есть идентичность? Ссылки и указатели -- объекты двойной идентичности. Поскольку с ними связаны объекты, на которые они указывают.
Как почтовый адрес на конверте.

Ш>>Это тоже записано в Стандарте? Где?


ПК>В разных местах. Во-первых, четко видно, что стандарт разделяет объекты, функции и ссылки, никогда не смешивая одно с другим (1.3.9, 3.5 и т.п.). Во-вторых, определение объекта (1.8) говорит, что объект — область памяти; ссылка не обязательно имеет ассоциированную с ней область памяти. То же определение говорит, что объект имеет object type; п. 3.9/9 совершенно четко говорит, что ни функциональные, ни ссылочные типы не являются объектными. В-третьих, если бы ссылки являлись объектами, многие пункты стандарта утратили бы смысл или были бы противоречивыми (3.9/4 и т.п.). В общем, здесь скорее имеет смысл говорить о том, что стандарт нигде не подтверждает идею о том, что ссылки являются объектами.


Любая "маленькая" переменная не обязательно имеет ассоциированную с ней область памяти. Но это просто результат оптимизации. По-моему, это всё просто ещё один из дефектов стандарта. Результат попыток намазать кусок масла на слишком большой кусок хлеба. Поскольку телепатию ещё не изобрели, если я передаю в функцию агрумент "по ссылке", то при этом необходимо записать в стек адрес этой переменной. Т.е. ссылка всё-таки -- особый объект, трактуемый по отдельным правилам. Или если хотите, элемент данных.

Ш>>Во всяком случае, ведёт она себя так же как обычный временный объект.


ПК>Объект, или значение? Например, int(10) объектом не является...


ПК>

ПК>A reference is an alternative name for an object.


ПК>Т.е. ссылка не является объектом сама по себе, а лишь служит еще одним именем для некоторого объекта. Также имеет смысл посмотреть аналогичное стандартному, но чуть менее подробное и строгое определение объекта у Страуструпа (4.9.6).


Служит, но это не мешает ей быть самостоятельной величиной, равной машинному адресу объекта. Это не препятствие для того, что бы считаться объектом.

ПК>Вокруг typeof/decltype, вообще, много проблем (см., например, статью Страуструпа: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1527.pdf ); в настоящий момент обе известные мне реализации typeof (GCC, EDG) отбрасывают ссылку при выводе типа.


Ну, они обязаны это делать по стандарту (по 5/6). Либо, надо корректировать стандарт. Были времена, когда и типа bool в C++ не было.

Похоже, пора писать ФАК по ссылкам.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Q&A: lvalue и rvalue
От: Аноним  
Дата: 13.01.04 08:02
Оценка: 28 (1)
Здравствуйте, Павел Кузнецов, Вы писали:

А>>int main()
А>>{
А>>    int i;

А>>    ++i;        // well-defined behavior
А>>    i = i + 1;  // undefined behavior
А>>}

ПК>Не уверен, что мы понимаем друг друга... Почему во втором случае должно быть неопределенное поведение?..

В соответствии с 4.1/1, при lvalue-to-rvalue conversion неинициализированного объекта.
Если я правильно понял, в первом случае lvalue-to-rvalue conversion не происходит.
Re[6]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 13.01.04 11:28
Оценка: 36 (2)
Здравствуйте, Шахтер, Вы писали:

Ш> Это наследие старого программирования, в котором не различался объект

Ш> и его адрес.

Кстати, объект и его адрес весьма тесно связаны. hint: у всех объектов в C++
есть адреса.

ПК>>>> ссылка объектом не является.


Ш>>> Это почему ещё не является?


ПК>> У ссылок нет основных атрибутов, присущих объектам: состояния и —

ПК>> что главное — identity (забыл как это по-русски).

Ш> Почему это нет? То, что состояние ссылки нельзя изменить, не значит,

Ш> что его нет.

Ну, здесь можно согласиться: состоянием ссылки можно было бы назвать связь с
объектом, на который она ссылается, так же, как это делается для указателей.
Но одного этого недостаточно: так можно было бы значение 10 считать объектом.

Ш> identity -- наверное идентичность?


Это фундаментальное понятие объектно-ориентированного программирования.
Действительно, в переводе того же Гради Буча "identity" переведено как
"идентичность":

Полезно понимать, что объект это нечто, имеющее четко определенные границы,
но этого недостаточно, чтобы отделить один объект от другого или дать оценку
качества абстракции. На основе имеющегося опыта можно дать следующее
определение:

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


...

Идентичность

Семантика. Хошафян и Коуплэнд предложили следующее определение:

"Идентичность — это такое свойство объекта, которое отличает его от всех
других объектов".


Они отмечают, что "в большинстве языков программирования и управления базами
данных для различения временных объектов их именуют, тем самым путая адресуемость
и идентичность. Большинство баз данных различают постоянные объекты по ключевому
атрибуту, тем самым смешивая идентичность и значение данных". Источником множества
ошибок в объектно-ориентированном программировании является неумение отличать
имя объекта от самого объекта.


В C++ с идентичностью тесно связан адрес объекта. У ссылок адреса, в частности,
и identity, вообще, нет (имя переменной к identity не относится).

Ш> А у указателя есть идентичность?


Да. Переменная-указатель сама является объектом и обладает собственным состоянием,
поведением и — что главное — идентичностью (в частности, у нее есть свой адрес).
rvalue типа указатель объектом не является, а является значением.

Ш> Ссылки и указатели -- объекты двойной идентичности. Поскольку с ними связаны

Ш> объекты, на которые они указывают.

Это сюда не относится. В лучшем случае, объект, на который ссылается ссылка,
можно считать ее состоянием. В противном случае получится, что две ссылки,
ссылающиеся на один и тот же объект неразличимы, что противоречит определению
identity.

ПК>> Во-первых, четко видно, что стандарт разделяет объекты, функции и ссылки,

ПК>> никогда не смешивая одно с другим (1.3.9, 3.5 и т.п.). Во-вторых,
ПК>> определение объекта (1.8) говорит, что объект — область памяти;
ПК>> ссылка не обязательно имеет ассоциированную с ней область памяти.
ПК>> То же определение говорит, что объект имеет object type; п. 3.9/9
ПК>> совершенно четко говорит, что ни функциональные, ни ссылочные типы не
ПК>> являются объектными. В-третьих, если бы ссылки являлись объектами, многие
ПК>> пункты стандарта утратили бы смысл или были бы противоречивыми (3.9/4 и
ПК>> т.п.).

Ш> Любая "маленькая" переменная не обязательно имеет ассоциированную

Ш> с ней область памяти.

Семантически — обязательно, в частности можно даже взять адрес этой
памяти.

Ш> Но это просто результат оптимизации.


Это уже не существенно: для ссылок безо всякой оптимизации не гарантируется
наличие ассоциированной с ними памяти. Фактическое выделение/не выделение
памяти для ссылок в каких-то конкретных случаях не имеет значения, т.к.
необходимость использовать для ссылок память в некотором случае никак
не влияет на семантику языка: в частности, адрес у ссылки так не появится.

Ш> если я передаю в функцию агрумент "по ссылке", то при этом необходимо

Ш> записать в стек адрес этой переменной.

Это детали реализации, к семантике языка отношения не имеющие.

Ш> Т.е. ссылка всё-таки -- особый объект, трактуемый по отдельным правилам.

Ш> Или если хотите, элемент данных.

Это элемент внутренних данных транслятора.

ПК>> Т.е. ссылка не является объектом сама по себе, а лишь служит

ПК>> еще одним именем для некоторого объекта. Также имеет смысл посмотреть
ПК>> аналогичное стандартному, но чуть менее подробное и строгое определение
ПК>> объекта у Страуструпа (4.9.6).

Ш> Служит, но это не мешает ей быть самостоятельной величиной, равной

Ш> машинному адресу объекта.

Вот. Ссылку можно считать величиной, значением, но уж никак не объектом. Точно
так же адрес объекта объектом не является, а является значением. А вот, скажем,
переменная-указатель типа int* объектом является.

Ш> Это не препятствие для того, что бы считаться объектом.


Объектом считаться ей это — а также много чего другого, что было перечислено
ранее — мешает.

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

А вот ссылка, скажем, как экземпляр какого-нибудь класса Reference уровня
"внутренностей" какого-то компилятора C++, вполне может быть объектом.
Впрочем, к нашему обсуждению это уже не относится.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 13.01.04 12:50
Оценка:
Здравствуйте, Вы писали:

>
 А>>> int main()
 А>>> {
 А>>>    int i;

 А>>>    ++i;        // well-defined behavior
 А>>>    i = i + 1;  // undefined behavior
 А>>> }
 >


ПК>> Не уверен, что мы понимаем друг друга... Почему во втором случае должно

ПК>> быть неопределенное поведение?..

> В соответствии с 4.1/1, при lvalue-to-rvalue conversion неинициализированного

> объекта. Если я правильно понял, в первом случае lvalue-to-rvalue conversion
> не происходит.

Ага... Хороший вопрос Мое утверждение о том, что в первом случае lvalue-to-
rvalue conversion не происходит, следует считать неверным. И вот почему.

++i;

Согласно 5.3.2/2 это эквивалентно:
i += 1;

что в свою очередь, согласно 5.17/7, эквивалентно:
i = i + 1;

Здесь уже очевидно, что происходит lvalue-to-rvalue conversion.

Как обычно, "рассуждения на тему здравого смысла" проигрывают стандарту
Прошу прощения за неверную информацию в предыдущем сообщении.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: Q&A: lvalue и rvalue
От: Аноним  
Дата: 13.01.04 13:06
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>++i;

ПК>Согласно 5.3.2/2 это эквивалентно:

(Видимо, все же 5.3.2/1) Ага, теперь все прояснилось. Вчера я почему-то не заметил "not" в этой фразе, а дальше первой половины читать не стал. "adding 1" же счел явно недостаточным для явной отсылки к 5.7.

Спасибо.
Re[8]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 13.01.04 13:14
Оценка:
Здравствуйте, Вы писали:

> (Видимо, все же 5.3.2/1)


Да. Точно, не мой день

> Ага, теперь все прояснилось. <...> Спасибо.


Взаимно
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: Q&A: lvalue и rvalue
От: Рома Мик Россия http://romamik.com
Дата: 13.01.04 15:00
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

Читаю и удивляюсь. Все ведь достаточно просто. Ссылка — это сущность времени компиляции, а объект — времени исполнения. То есть какой код будет сгенерирован для обращения к ссылке решает компилятор и совсем не обязательно это будет разыменование указателя, вполне может быть и обращение к стеку.
... << RSDN@Home 1.1.2 beta 2 >>
Re[8]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 13.01.04 19:43
Оценка:
Здравствуйте, Рома Мик, Вы писали:

РМ>Читаю и удивляюсь. Все ведь достаточно просто. Ссылка — это сущность времени компиляции, а объект — времени исполнения. То есть какой код будет сгенерирован для обращения к ссылке решает компилятор и совсем не обязательно это будет разыменование указателя, вполне может быть и обращение к стеку.


Гм... То есть по твоей логике:
int f()
{
  int i = 10;
  return i;
}

i здесь не объект. А в этом случае:
int f(int& r)
{
  return r;
}

что вернет функция известно во время компиляции?
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 13.01.04 20:00
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В C++ с идентичностью тесно связан адрес объекта. У ссылок адреса, в частности,

ПК>и identity, вообще, нет (имя переменной к identity не относится).

Ага. Вот это уже понятнее. В принципе, идентичностью объекта в C++ можно считать его адрес (при условии, что мы знаем тип)(не очень хорошо выразился, скорее -- методом идетификации). У ссылки, действительно, нет адреса. Точнее говоря, этот адрес нельзя получить без хака. Более того, если ссылка соптимизирована компилятором, то никакой хак не поможет, а способа заставить компилятор "разоптимизировать" нет. В отличиии от случая соптимизированной переменной целого типа, скажем. Так что ссылку, действительно, правильно рассматривать не как объект, а как значение.
Я бы выразился ещё так -- ссылка, это не объект, а прокси объекта.

ПК>В противном случае получится, что две ссылки,

ПК>ссылающиеся на один и тот же объект неразличимы, что противоречит определению
ПК>identity.

Не совсем понял это утверждение. На самом деле, две ссылки ссылающиеся на один и тот же объект неразличимы. Это, по-моему, очевидно. Это примерно так же, как скажем две целые константные переменные с одним значение. Различить которые можно только по их адресам. Но поскольку у ссылок собственных адресов нет, точнее, даже если и есть, компилятор нам просто их не отдаст, то они неразличимы. Но опять же, неразличимость во внешних проявлениях не означает тождественность. Она может означать лишь недостаток мощности у синхрофазотрона. Copyright (c) мой
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[8]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 13.01.04 20:00
Оценка:
Здравствуйте, Рома Мик, Вы писали:

РМ>Здравствуйте, Павел Кузнецов, Вы писали:


РМ>Читаю и удивляюсь. Все ведь достаточно просто. Ссылка — это сущность времени компиляции, а объект — времени исполнения. То есть какой код будет сгенерирован для обращения к ссылке решает компилятор и совсем не обязательно это будет разыменование указателя, вполне может быть и обращение к стеку.


Когда класс vector возвращает тебе ссылку на затребованный объект, он что возвращает "сущность времени компиляции"? Я не думаю, что во время компиляции можно вычислить адрес этого объекта.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[8]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 13.01.04 20:40
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Я бы выразился ещё так -- ссылка, это не объект, а прокси объекта.




ПК>>В противном случае получится, что две ссылки, ссылающиеся на один и тот же объект неразличимы, что противоречит определению identity.


Ш>Не совсем понял это утверждение. На самом деле, две ссылки ссылающиеся на один и тот же объект неразличимы.


Ну, я, вероятно, недостаточно точно выразился. Я просто хотел сказать, что предложенная identity таковой не является, т.к. не позволяет различать ссылки. Судя по тому, что ты пишешь ниже, думаю, что в итоге мы друг друга вполне поняли:

Ш>Это, по-моему, очевидно. Это примерно так же, как скажем две целые константные переменные с одним значение. Различить которые можно только по их адресам. Но поскольку у ссылок собственных адресов нет, точнее, даже если и есть, компилятор нам просто их не отдаст, то они неразличимы.


Именно так. Это и есть то, что я имел в виду, говоря, что у ссылок нет identity.

Ш>Но опять же, неразличимость во внешних проявлениях не означает тождественность. Она может означать лишь недостаток мощности у синхрофазотрона. Copyright (c) мой




Хотел было для компромисса предложить назвать ссылки сущностями, но вовремя вспомнил, что entity — тоже термин спецификации C++. Эх... Нет совершенства в этом мире
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[9]: Q&A: lvalue и rvalue
От: Рома Мик Россия http://romamik.com
Дата: 13.01.04 20:55
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Когда класс vector возвращает тебе ссылку на затребованный объект, он что возвращает "сущность времени компиляции"? Я не думаю, что во время компиляции можно вычислить адрес этого объекта.

Фактически неизвестно насколько извращенным может оказаться результат в результате встраивания ( inline ) и оптимизации.

Рассмотрим только что придуманный мной пример, когда вектор точно знает на этапе компиляции адрес буфера, что в приницпе можно себе представить: если все данные из памяти для доступа мапятся на опреденный виртуальный адрес, например.
template< class T >
class vector
{
    const void * BASE = 0xffffffff;
    T    &operator[]( size_t n )
    {
        LockMemory();
        return *(T*)(BASE + n * sizeof( T ));
    }
};

В результате встраивания мы из vector[10] получим обращение по конкретному адресу.
... << RSDN@Home 1.1.2 beta 2 >>
Re[9]: Q&A: lvalue и rvalue
От: Рома Мик Россия http://romamik.com
Дата: 13.01.04 20:55
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

Я не то имел ввиду.
ИМХО объект ( на этапе выполненения ) — это область памяти, с которой ассоциирован тип. Про ссылку на этапе выполнения ничего сказать нельзя. Например, может вообще не быть никакой области памяти, соответсвующей ссылке. С большой вероятностью так и будет для такого кода:
int i;
int &a = i;
... << RSDN@Home 1.1.2 beta 2 >>
Re[9]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 13.01.04 20:56
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Хотел было для компромисса предложить назвать ссылки сущностями, но вовремя вспомнил, что entity — тоже термин спецификации C++. Эх... Нет совершенства в этом мире


По моему, термин объект просто перегружен. Сильно.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.