Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 07.01.04 14:57
Оценка: 529 (34) +3
Статья:
Q&A: lvalue и rvalue
Автор(ы): Павел Кузнецов
Дата: 02.01.2004
lvalue и rvalue — что это такое.


Авторы:
Павел Кузнецов

Аннотация:
lvalue и rvalue — что это такое.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Q&A: lvalue и rvalue
От: Аноним  
Дата: 07.01.04 15:18
Оценка:
в выражении ++i (которое l-value) будет иметь место l-value to r-value преобразование (т.е. тут ведь необходимо получить старое значение) ? При передаче по значению в функцию объекта (допустим с нетривиальным копированием) преобразование есть?
Re[2]: Q&A: lvalue и rvalue
От: jazzer Россия Skype: enerjazzer
Дата: 07.01.04 20:35
Оценка:
Здравствуйте, Аноним, Вы писали:

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


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

A>При передаче по значению в функцию объекта (допустим с нетривиальным копированием) преобразование есть?


оно есть всегда, когда нужно значение. И здесь в том числе.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Q&A: lvalue и rvalue
От: jazzer Россия Skype: enerjazzer
Дата: 07.01.04 20:40
Оценка: 14 (1)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Статья:



ПК>Авторы:

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

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

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

все, окончательно надоело давать ссылку на свое старое сообщение "ну поехали"? ;)

а давайте все часто цитируемые сообщения сделаем статьями!
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 08.01.04 08:09
Оценка: +1
Здравствуйте, jazzer, Вы писали:

J>а давайте все часто цитируемые сообщения сделаем статьями!


Ага, такая идея уже давно витает: надо ж как-то Q&A (aka FAQ) делать...
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Q&A: lvalue и rvalue
От: Кодт Россия  
Дата: 08.01.04 09:06
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

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


Пример с ложным lvalue:
class C
{
public:
  C /* no const */ * operator& () /* no const */ { return this; }
};

main()
{
  &(C()); // OK
}

По-моему, здесь ОК только у VC6, который не навязывает временным объектам константности.


Еще стоит упомянуть о rvalue-to-lvalue conversion, то есть адресации к временным объектам — аргументам функций и экземплярам классов (по сути, любое обращение к члену-данному или методу временного объекта требует такую конверсию).
Перекуём баги на фичи!
Re[2]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 08.01.04 11:25
Оценка:
Здравствуйте, Кодт, Вы писали:

К> Пример с ложным lvalue:

К>
 К> class C
 К> {
 К> public:
 К>   C /* no const */ * operator& () /* no const */ { return this; }
 К> };

 К> int main()
 К> {
 К>   &(C()); // OK
 К> }
 К>


К> По-моему, здесь ОК только у VC6, который не навязывает временным

К> объектам константности.

В том-то и дело, что этот пример не требует константности. Более того, временные
объекты не являются константными. Они являются rvalue, но не константами.
Объект был бы константным при таком способе создания:
int main()
{
  typedef const C CC;
  &CC(); // ERROR
}

Суть в том, что для неконстантных rvalue класс-типов можно вызывать некотстантные
функции-члены. Например:
class C
{
public:
  void f() { }
};

int main()
{
  C().f(); // OK
  return 0;
}

Соответственно, если мы определяем свой operator&, как в первоначальном примере:
class C
{
public:
  C* operator& () { return this; }
};

то строка:
&C();

будет эквивалентна такой:
C().operator&();

что разрешено спецификацией языка C++.

Кста, в отношении "ОК только у VC6"... Твой вариант, с дополнительными скобками:
"&(C());" вызывает некоторые затруднения у GCC, если ты об этом. В первоначальном
виде: "&C();" пример компилируется всеми доступными мне современными
компиляторами.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Q&A: lvalue и rvalue
От: Кодт Россия  
Дата: 08.01.04 15:11
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Суть в том, что для неконстантных rvalue класс-типов можно вызывать некотстантные функции-члены.


Тогда я решительно не понимаю, почему
struct RValue
{
  void modify();
  void test() const;
};

void modify(RValue& v) { v.modify(); }
void test(RValue const& v) { v.test(); }

void main()
{
  RValue().modify(); // можно
  RValue().test();

  modify(RValue()); // низзя!
  test(RValue());
}

Смысл где?
Перекуём баги на фичи!
Re: Q&A: lvalue и rvalue
От: What Беларусь  
Дата: 08.01.04 17:42
Оценка: 1 (1)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В принципе, возможность применения к выражению встроенной операции получения адреса (унарная операция &) можно считать достаточным критерием того, что выражение является lvalue.


Непонятно: можно считать достаточным условием или это критерий (необходимое и достаточное условие)?
... << RSDN@Home 1.1.0 stable >>
Re[4]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 08.01.04 18:26
Оценка: +2
Здравствуйте, Кодт, Вы писали:

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


ПК>>Суть в том, что для неконстантных rvalue класс-типов можно вызывать некотстантные функции-члены.


К>Тогда я решительно не понимаю, почему

К>
К>struct RValue
К>{
К>  void modify();
К>  void test() const;
К>};

К>void modify(RValue& v) { v.modify(); }
К>void test(RValue const& v) { v.test(); }

К>void main()
К>{
К>  RValue().modify(); // можно
К>  RValue().test();

К>  modify(RValue()); // низзя!
К>  test(RValue());
К>}
К>

К>Смысл где?

Цитата из Страуса.

Disallowing conversions for nonconst reference arguments (§5.5) avoids the possibility of silly mistakes arising from the introduction of temporaries. For example:

void update(float& i) ;

void g(double d, float r)
{
update(2.0f) ; / / error: const argument
update(r) ; / / pass ref to r
update(d) ; / / error: type conversion required
}

Had these calls been allowed, update() would quietly have updated temporaries that immediately
were deleted. Usually, that would come as an unpleasant surprise to the programmer.

... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 08.01.04 18:38
Оценка:
Здравствуйте, What, Вы писали:

ПК>>В принципе, возможность применения к выражению встроенной операции получения адреса (унарная операция &) можно считать достаточным критерием того, что выражение является lvalue.


W>Непонятно: можно считать достаточным условием или это критерий (необходимое и достаточное условие)?


Спасибо за уточнение. Конечно, достаточное условие.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Q&A: lvalue и rvalue
От: What Беларусь  
Дата: 09.01.04 15:13
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>>>В принципе, возможность применения к выражению встроенной операции получения адреса (унарная операция &) можно считать достаточным критерием того, что выражение является lvalue.


ПК>Спасибо за уточнение. Конечно, достаточное условие.


Не могли бы Вы тогда привести пример lvalue, для которого нельзя применить встроенную операцию получения адреса?
... << RSDN@Home 1.1.0 stable >>
Re[4]: Q&A: lvalue и rvalue
От: achp  
Дата: 09.01.04 15:16
Оценка: 2 (1)
Здравствуйте, What, Вы писали:

W>Не могли бы Вы тогда привести пример lvalue, для которого нельзя применить встроенную операцию получения адреса?


lvalue любого типа, в котором перегружена операция взятия указателя (унарный &).
Да здравствует ИМХО!
Re[5]: Q&A: lvalue и rvalue
От: What Беларусь  
Дата: 09.01.04 15:27
Оценка:
Здравствуйте, achp, Вы писали:

W>>Не могли бы Вы тогда привести пример lvalue, для которого нельзя применить встроенную операцию получения адреса?


A>lvalue любого типа, в котором перегружена операция взятия указателя (унарный &).


По-моему это просто другая трактовка слов "нельзя применить". А операцию получения адреса можно вызвать, как я понял из статьи, и у rvalue.
... << RSDN@Home 1.1.0 stable >>
Re[6]: Q&A: lvalue и rvalue
От: Кодт Россия  
Дата: 09.01.04 19:42
Оценка: 2 (1)
Здравствуйте, What, Вы писали:

W>По-моему это просто другая трактовка слов "нельзя применить". А операцию получения адреса можно вызвать, как я понял из статьи, и у rvalue.


Как раз у rvalue адреса нет. Если же перекрыть метод operator&, то это означает, что автор сам на свой страх и риск делает рукоятку для возвращения указателя. Какой он смысл вкладывает в этот указатель — дело десятое
class RValue // глупость какая-то...
{
    static RValue* single_;
    RValue* aggregate_;
public:
    RValue(int indirection) { aggregate_ = (indirection<=0) ? this : new RValue(indirection-1); }
    ~RValue() { if(this != aggregate_) delete aggregate_; }

    RValue* somePtr() { return aggregate_; }
    RValue* anotherPtr() { return this; }
    RValue* thirdPtr() { return single_; }
    
    RValue* operator&() { в зависимости от смысла, выполняет somePtr|anotherPtr|thirdPtr (); }
};



Одно из практических применений (возможно) — это вызов com-методов, возвращающих ненужный out-параметр.
struct ISome
{
    STDMETHOD(getManyObjects)(/*out*/ IAnother** ppA, /*out*/ IThird** ppB);
};

...
CComPtr<IAnother> pA;
pSome->getManyObjects( &pA, &CComPtr<IThird>() );    // & - указатель на член IXXX* m_ptr
...



Чтобы обскакать перекрытый &, может пригодиться такая конструкция
template<class T> T* addressof(T& var)
{
    return reinterpret_cast<T*>(&reinterpret_cast<char&>(var));
}

/////////////////////////////////////////////////////
// пример

class Hide
{
public:
    virtual ~Hide() {}    // чтобы какое-нибудь содержание было (vfptr в данном случае)

    // для отладки функции addressof
    Hide* self() { return this; }
    Hide const* self() const { return this; }
private:
    // А пофиг, какой возвращаемый тип. Все одно private...
    void operator& () {}
    void operator& () const {}
};

int main()
{
    Hide h;
    Hide* ph1 = &h;    // здесь будет ошибка.
    Hide* ph2 = addressof(h);
    assert(ph2 == h.self());
}
... << RSDN@Home 1.1.0 stable >>
Перекуём баги на фичи!
Re[6]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 09.01.04 20:06
Оценка: 1 (1)
Здравствуйте, What, Вы писали:

W>>>Не могли бы Вы тогда привести пример lvalue, для которого нельзя применить встроенную операцию получения адреса?


A>>lvalue любого типа, в котором перегружена операция взятия указателя (унарный &).


W>По-моему это просто другая трактовка слов "нельзя применить".


Т.е. другая? При наличии переопределенной операции operator & осуществить "вызов" встроенной не получится.

W>А операцию получения адреса можно вызвать, как я понял из статьи, и у rvalue.


Но не встроенную, а переопределенную.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 09.01.04 21:38
Оценка: 12 (1)
Здравствуйте, Вы писали:

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


Важно различать доступ к старому значению и lvalue-to-rvalue conversion. Последнее происходит в тех случаях, когда lvalue используется в контексте, где ожидается rvalue. lvalue-to-rvalue conversion, обычно — создание временного объекта, имеющего то же значение, что и исходное lvalue. То, что при выполнении операции инкремента так или иначе потребуется получить старое значение вовсе не означает, что должно происходить lvalue-to-rvalue conversion. Очень грубо можно провести следующую аналогию. Представим, что i имеет тип int и операция ++ для int реализована функцией int& operator ++(int&) (конечно, в C++ это не так, но сейчас мы "забудем" об этом нюансе). Тогда выражение:
++i;

Можно будет записать в таком виде:
operator ++(i);

При "вызове" произойдет привязка параметра-ссылки int& к аргументу i, являющемуся lvalue. Никаких преобразований к rvalue не требуется. Что будет происходить далее, "внутри" "функции", нас не касается: она для нас — черный ящик. Результатом функции является int&, т.е. lvalue типа int. Вне зависимости от того, что никакой функции operator ++(int&) нет, внутренняя механика операции ++ к lvalue-to-rvalue преобразованиям не имеет.

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

Как выяснили в http://rsdn.ru/forum/?mid=505392
Автор: Павел Кузнецов
Дата: 13.01.04
lvalue-to-rvalue conversion в этом случае, все-таки, происходит. -- ПК

А вот если бы результат выражения ++i использовался, например, так:
int j;
j = ++i;

тогда — да, имело бы место lvalue-to-rvalue conversion; впрочем, естественно, это верно для любого lvalue-выражения типа int, стоящего в правой части. Почему здесь происходит lvalue-to-rvalue conversion? Потому что, т.к. левый операнд имеет не класс-тип, правое выражение неявно приводится к типу int (5.17/3), и т.к. тип, к которому производится неявное преобразование, не является ссылочным, результат преобразования — rvalue (4/3).

А>При передаче по значению в функцию объекта (допустим с нетривиальным копированием) преобразование есть?


Т.е., если я правильно понял, ситуация вроде такой:
class C
{
public:
  C(const C&);
};

void f(C t);

int main()
{
  C c;
  f(c);
}

При вызове подобной функции происходит copy-initialization параметра выражением аргумента. Т.е. в данном случае параметр инициализируется таким образом:
C t = c;

Это приводит к вызову конструктора копирования C::C(const C&). Параметр конструктора копирования — ссылка const C&; т.к. она инициализируется lvalue-выражением c, она должна быть привязана непосредственно, без создания временных объектов (8.5.3/5); lvalue-to-rvalue, array-to-pointer и function-to-pointer conversions в этом случае подавляются. Сам конструктор — и будет ли "внутри" него происходить чтение "значения" c — для нас не важен: это уже лишняя "механика".

Проще говоря, lvalue-to-rvalue conversion здесь не происходит.

lvalue-to-rvalue conversions для lvalue-выражений класс-типов производятся, когда lvalue-выражение использовано в контексте, требующем rvalue. Например:
C c;
foo() ? C() : c;

В этом случае lvalue-выражение c приводится к rvalue типа C (5.16/3).
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 09.01.04 21:44
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>lvalue-to-rvalue conversions для lvalue-выражений класс-типов производятся, когда lvalue-выражение использовано в контексте, требующем rvalue. Например:

ПК>
ПК>C c;
ПК>foo() ? C() : c;
ПК>

ПК>В этом случае lvalue-выражение c приводится к rvalue типа C (5.16/3).

P.S. естественно, есть и более простые случаи, когда мы сами, явно, "запрашиваем" lvalue-to-rvalue conversion. Например:
static_cast<C>(c);
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: Q&A: lvalue и rvalue
От: What Беларусь  
Дата: 09.01.04 21:58
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Т.е. другая? При наличии переопределенной операции operator & осуществить "вызов" встроенной не получится.


Да, я это и хотел сказать, но сделал как-то не по-русски.

W>>А операцию получения адреса можно вызвать, как я понял из статьи, и у rvalue.


ПК>Но не встроенную, а переопределенную.


Именно так.

А всё-таки, не могли бы Вы тогда привести пример lvalue, для которого нельзя применить встроенную операцию получения адреса?
... << RSDN@Home 1.1.0 stable >>
Re[8]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 09.01.04 22:10
Оценка: 2 (1)
Здравствуйте, What, Вы писали:

W>привести пример lvalue, для которого нельзя применить встроенную операцию получения адреса?


В статье есть, да и achp привел +- тот же пример... Если есть переопределенная унарная operator &, вызвать встроенную уже не выйдет. Во всяком случае именно это и подразумевалось в Q&A. В общем, думаю, надо там формулировку чуть-чуть уточнить, чтобы статья давала ответы на вопросы, а не порождала все новые и новые
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
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. Парадоксы
Re[10]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 13.01.04 21:01
Оценка: +1
Здравствуйте, Рома Мик, Вы писали:

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


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

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

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


То, что в результате оптимизации в подходящих ситуациях компилятор может очень многое выбросить из кода и из памяти, я думаю, совершенно понятно. Вопрос в другом. "Сущность времени компиляции" должна гарантирована быть вычисляема во время компиляции. Для ссылок таких гарантий, естественно, дать невозможно.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[11]: Q&A: lvalue и rvalue
От: Рома Мик Россия http://romamik.com
Дата: 13.01.04 21:48
Оценка:
Здравствуйте, Шахтер, Вы писали:

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

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

Ш>"Сущность времени компиляции" должна гарантирована быть вычисляема во время компиляции.

А это я неверно использую термины Имелось ввиду, что понятие ссылка существует только на этапе компиляции, в отличие от объекта, который наоборот существует только на этапе выполнения, а на этапе компиляции существует мнение, что объекту — быть ( но этапе выполнения ).
... << RSDN@Home 1.1.2 beta 2 >>
Re[12]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 13.01.04 22:05
Оценка: +1
Здравствуйте, Рома Мик, Вы писали:

РМ>А это я неверно использую термины Имелось ввиду, что понятие ссылка существует только на этапе компиляции, в отличие от объекта, который наоборот существует только на этапе выполнения, а на этапе компиляции существует мнение, что объекту — быть ( но этапе выполнения ).


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

Ш>Ну, вообще-то на этапе выполнения ничего, кроме сигналов на линиях нет. 0,1,фронт. Между прочим, разглядывая сигналы на ножках процессора на экране осцилографа или логического анализатора, начинаешь задумываться о сущности бытия. Все эти объекты, ссылки и прочее на самом деле суть абстрактные понятия, существующие только в голове. Их даже в тексте программы нет. Это мы, читая текст придаём ему смысл. (с) Ещё один Copyright (c) мой.

Оно конечно да, несомненно. Но указанные сигналы можно как-то интерпретировать. Так вот, объективно существует память, последоватльность битов. И любому объекту в этой памяти соответсвует группа битов. Хотя это соответствие, конечно, чисто умозрительное на этапе выполнения, но оно есть. А ссылке уже ничего не соответствует. И наоброт, во время компиляции ссылке соответсвует нечто более реальное, чем объекту, которому соответствует только знание, что на этапе выполнеия он будет.
... << RSDN@Home 1.1.2 beta 2 >>
Re[14]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 13.01.04 23:02
Оценка:
Здравствуйте, Рома Мик, Вы писали:

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


Ш>>Ну, вообще-то на этапе выполнения ничего, кроме сигналов на линиях нет. 0,1,фронт. Между прочим, разглядывая сигналы на ножках процессора на экране осцилографа или логического анализатора, начинаешь задумываться о сущности бытия. Все эти объекты, ссылки и прочее на самом деле суть абстрактные понятия, существующие только в голове. Их даже в тексте программы нет. Это мы, читая текст придаём ему смысл. (с) Ещё один Copyright (c) мой.

РМ>Оно конечно да, несомненно. Но указанные сигналы можно как-то интерпретировать. Так вот, объективно существует память, последоватльность битов. И любому объекту в этой памяти соответсвует группа битов. Хотя это соответствие, конечно, чисто умозрительное на этапе выполнения, но оно есть. А ссылке уже ничего не соответствует. И наоброт, во время компиляции ссылке соответсвует нечто более реальное, чем объекту, которому соответствует только знание, что на этапе выполнеия он будет.

Ну почему же не соответствует-то? Точно так же, есть место в стеке или в статической памяти, где лежит значение этой ссылки -- на самом деле просто машинный адрес объекта, на который эта ссылка ссылается. Тут даже не надо долго фантазировать, достаточно посмотреть какой-нибудь простой примерчик на ассемблере.

Самоцитирование. Простейший примерчик.

inline void swap(int &a,int &b)
 {
  int temp=a;
  
  a=b;
  
  b=temp;
 }


PUBLIC    ?swap@@YAXAAH0@Z                ; swap
; Function compile flags: /Ogty
; File c:\ss_root\c++\projects\test\main.cpp
;    COMDAT ?swap@@YAXAAH0@Z
_TEXT    SEGMENT
_a$ = 8                            ; size = 4
_b$ = 12                        ; size = 4
?swap@@YAXAAH0@Z PROC NEAR                ; swap, COMDAT

; 10   :   int temp=a;
; 11   :   
; 12   :   a=b;

    mov    edx, DWORD PTR _b$[esp-4] // вот здесь лежит ссылка b
    mov    eax, DWORD PTR _a$[esp-4] // а вот ссылка a
    mov    ecx, DWORD PTR [eax]      // вот мы загрузили в регистр значение целой переменной, на которую ссылалась ссылка a
    push    esi
    mov    esi, DWORD PTR [edx]
    mov    DWORD PTR [eax], esi

; 13   :   
; 14   :   b=temp;

    mov    DWORD PTR [edx], ecx
    pop    esi

; 15   :  }

    ret    0
?swap@@YAXAAH0@Z ENDP                    ; swap
_TEXT    ENDS
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[15]: Q&A: lvalue и rvalue
От: Рома Мик Россия http://romamik.com
Дата: 14.01.04 09:17
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Ну почему же не соответствует-то? Точно так же, есть место в стеке или в статической памяти, где лежит значение этой ссылки -- на самом деле просто машинный адрес объекта, на который эта ссылка ссылается.

Да не обязательно. О чем я и толкую. Как будет реализована ссылка и будет ли указатель зависит от компилятора. Для
int a;
int &i = a;

очень легко может не быть никакого указателя. А если он и будет, то это детали реализации. Форсировать создание объекта a ты можешь получив его адрес, он обязан адрес иметь, а со ссылкой такого сделать нельзя, так как адрес объекта ссылки ( а не объекта, на который она ссылается ) получить нельзя, так как его нету.
... << RSDN@Home 1.1.2 beta 2 >>
Re[10]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 14.01.04 10:16
Оценка:
Здравствуйте, Рома, Вы писали:

РМ> Например, может вообще не быть никакой области памяти, соответсвующей

РМ> ссылке. С большой вероятностью так и будет для такого кода:
РМ>
 РМ> int i;
 РМ> int &a = i;
 РМ>


При включенной оптимизации с вероятностью 99% для переменной i в следующем
примере также не будет зарезервировано никакой области памяти:
int f()
{
  int i = 10;
  return i;
}

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

ПК>тем не менее, i обозначает объект типа int.

Но можно получить адрес i и тогда объект i обязательно будет. А невстроенный объект ( которые не совсем такие, как все остальные ) будет обязательно всегда. Форсировать создание ссылки ты никак не можешь, поскольку не предлагается никакой возможности получить адрес объекта ссылки, поскольку такого объекта не предполагается.
... << RSDN@Home 1.1.2 beta 2 >>
Re[12]: Q&A: lvalue и rvalue
От: Павел Кузнецов  
Дата: 14.01.04 11:15
Оценка:
Здравствуйте, Рома, Вы писали:

ПК>> тем не менее, i обозначает объект типа int.


РМ> Но можно получить адрес i


Вот это и является основным моментом, а не фактическое использование/не
использование памяти для переменной.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[12]: Q&A: lvalue и rvalue
От: Шахтер Интернет  
Дата: 14.01.04 19:15
Оценка:
Здравствуйте, Рома Мик, Вы писали:

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


ПК>>тем не менее, i обозначает объект типа int.

РМ>Но можно получить адрес i и тогда объект i обязательно будет. А невстроенный объект ( которые не совсем такие, как все остальные ) будет обязательно всегда.

Тоже не всегда.

РМ>Форсировать создание ссылки ты никак не можешь, поскольку не предлагается никакой возможности получить адрес объекта ссылки, поскольку такого объекта не предполагается.


Конец предложения неверен. Он как раз предполагается, пусть это с точки зрения программиста и "неполноценный объект", просто компилятор может, если сможет, его элиминировать, точно так же, как и объект любого другого типа.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Q&A: lvalue и rvalue
От: is  
Дата: 15.01.04 15:02
Оценка: 1 (1)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>[...] identity (забыл как это по-русски).


Идентичьность (identity) объекта
Автор: Ватакуси
Дата: 30.12.03


Re[5]: Вопросы на собеседовании
Автор: Alexey Shirshov
Дата: 01.12.03
Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius — and a lot of courage — to move in the opposite direction. -- Albert Einstein
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.