Здравствуйте, alex_ant, Вы писали:
_>Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
Разница в том, что ссылка — это второе имя переменной. И на этапе компиляции компилятор заменяет ссылку нужным именем. Вот и все.
In C++, pointers are objects: they have identity, manifested by a
unique address. References are *not* objects, and do not have
identity. References define a name equivalence; semantically, they
are more closely related to the Fortran `equivalence' statement than
they are to pointers.
A simple example:
struct A { int &a1 ; int &a2 ; } a ;
struct B { int *b1 ; int *b2 ; } b ;
What is guaranteed by the standard: first, sizeof( A ) >= 1 (since A
is an object, although it contains no objects), whereas sizeof( B ) >=
2, since B contains two objects, each of which must have a positive
size. Second: &b.b1 != &b.b2, since b1 and b2 are objects, and must
have an identity manifested by a distinct address. There is no such
guarantee concerning a1 and a2.
и еще одна:
Why don't you read the quote from the C++ standard. There is *no*
case where a reference must occupy storage. A simple example:
struct A
{
int& ri ;
int i ;
A() ;
} ;
In this structure, it is perfectly possible that the offset of i == 0.
Compare:
struct B
{
int *const pi ;
int i ;
B() ;
} ;
A a ;
B b ;
// This assert is *not* guaranteed.
assert( (void*)( &a.i ) != (void*)( &a ) ) ;
// This one is.
assert( (void*)( &b.i ) != (void*)( &b ) ) ;
As both Pete Becker and Steve Clamage have pointed out, a pointer *is*
an object, and must occupy storage. From an OO point of view, a
pointer has identity, which in C++ is materialized by a unique
address. A reference has no such identity, but simply introduce a
name alias, and so requires no such unique address.
Так получилось, что моя работа связана с производством требовательным к уровням надежности и устойчивости. Поэтому я *вынужден* работать только со стандартами. Если в стандарте С++ написано (а там написано ) "a reference can be thought of as a name of an object", я буду верить именно стандарту, но ни кому-нибудь еше. И никакими философскими рассуждениями вы меня не переубедите. Извиняйте.
Здравствуйте, alex_ant, Вы писали:
_>Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
1. Ссылка уже разименована.
2. Ссылка не мжет быть NULL
3. Указатель можно инициализировать много раз, ссылку — ровно один.
Здравствуйте, memorilik, Вы писали:
M>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>В стек в языке С++ ничего не кладется. Потому что в С++ нет никакого аппаратного стека. M>А в языке ассемблер какой стек ? Аппаратный ? Или, перефразирую одну шутку, — "язык С++ намного эффективнее ассемблера потому, что выполняет многие команды минуя процессор" ? Стек, он и в Африке — стек. И аппаратный он бывает тока на специализированном железе.
Вынужден тебя разочаровать. В процессоре x86 есть именно аппаратный стек. И регистр ESP именно на него показывает.
PD>>А в рабочей программе туда кладется в обоих случаях адрес переменной. А адрес — такого понятия в С++ тоже нет. M>Куда — туда ? В стек ? И адрес — такое понятие в С++ есть. Адрес — это _значение_ указателя.
Можете его даже распечатать, например .
Распечатать можно именно сам указатель. В формате %d или %x или %p. Равно как можно распечатать переменную типа int.
А вот то , что значением указателя является именно адрес — ссылку на стандарт, пожалуйста. Потому что это , вообще говоря, неверно. Адрес — понятие машинно-зависимое. И вообще, что такое адрес ? К примеру, для x86 — какой именно адрес ? Надеюсь, тебе известно, что численным значением указателя является виртуальный адрес в смысле страничного механизма x86. А еще есть физический адрес, его тебе не видать в программе 3 кольца на С++ как своих ушей . Такие понятия в машинно-независимый язык закладываться не могут.
Здравствуйте, pullover, Вы писали: LM>>2. Ссылка не мжет быть NULL P>
P> int val = 10;
P> int *p = &val;
P> // жил был указатель, тут его обнуляем...
P> p = NULL;
P> // а здесь получаем ссылку. увы ссылка нулевая и проверить уже никак не можем.
P> int &ref = *p;// ВОТ ТУТ МЫ ПОЛУЧАЕМ НЕОПРЕДЕЛЕННОЕ ПОВЕДЕНИЕ
P> ref++;// А этот код вполне корректен
P>
Можно ли сунуть пальцы в розетку? Можно! Но зачем?!
Когда я говорю "не может быть NULL" я имею ввиду следующее:
class A;
void Foo(A& ref)
{
ref.CallSomeFoo();// Код полностью корректен
};
void Foo(A* ptr)
{
ptr->CallSomeFoo();// Код не корректен. Получаем интересное поведение при передаче нулевого указателя и по ушам от начальства :maniac:
}
Здравствуйте, Вумудщзук, Вы писали:
В>только я бы сказал, что форум — не место для изучения азов: разница между ссылкой и указателем описана в любой книжке по с++
Страуструп в "ЯП C++, Спец издание" дает описание ссылки на странице 137. А спустя 300 страничек показывает еще одно отличие (разное поведение при dynamic_cast), которое сам называет фундаментальным.
Такой разброс хоть и вызывает недоумение, но является логичным для учебника. Вот и получается, что иногда, кроме как на сильном форуме, увидеть полный список отличий негде.
Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
Здравствуйте, alex_ant, Вы писали:
_>Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
2.3.10
Ссылка является другим именем объекта... Очевидным способом реализации ссылки является константный
указатель...
2.4.6
...компилятор может несколькими путями
воспользоваться тем, что объект является константой (конечно, в
зависимости от того, насколько он сообразителен). Самое очевидное —
это то, что для константы не требуется выделять память, поскольку
компилятор знает ее значение.
"alex_ant" <52470@users.rsdn.ru> wrote in message news:1883420@news.rsdn.ru... > Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
По своему внутреннему представлению указатель и ссылка действительно одинаковы.
А вот с точки зрения использования, разница состоит в следующем:
1. Указатель можно перенаправить на другой объект, ссылка же инициализируется только один раз при создании и не может быть перенаправлена.
2. Для доступа к данным через указатель используются операторы * и ->. Так же к указателю применим оператор индексирования []. Доступ к данным по ссылке по форме выглядит так, как будто работа идет непосредственно с самой переменной, если это структура или класс, то доступ к членам осуществляется через оператор "точка".
3. Результатом взятия адреса указателя является адрес ячейки памяти, в которой хранится сам указатель. Адресом ссылки же будет адрес объекта, адресуемого ссылкой.
4. Ссылка может обеспечвать время жизни временной переменной: пока жива ссылка, будет жива и временная переменная.
Если говорить коротко, то ссылку можно считать указателем, который всегда разыменован автоматически.
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, pavel_turbin, Вы писали:
_>все эти "различия" -- только синтаксис языка. в объектном коде и ссылка, и указатель -- это адрес. Соответственно, с ними можно делать все, что душе угодно:
Не совсем так.В стандарте (раздел 8.3.2) явно прописано:
3 It is unspecified whether or not a reference requires storage (3.7).
Оттуда же (в clause 1):
Note: a reference can be thought of as a name of an object.
_>
_> int a = 0;
_> int &b = a; // b ссылается на a
_> int c = 1;
_> __asm lea eax,[c]
_> __asm mov dword ptr [b],eax
_> /* теперь b ссылается на c */
_> b = 2; // c равно 2, а -- 0
_> __asm mov dword ptr [b], 0
_> // теперь b равен нулю.
_>
_>PS. Можно и без asm, просто так нагляднее.
Таким образом, приведенный фрагмент кода может неоткомпилироваться по причине несуществования b. Т. е. в исходном тексте на С++ это имя определено. Но в процессе компиляции компилятор вместо b может (и имеет право) использовать непосредственно переменную a.
Вот другой пример кода (компилятор VC7.1):
int volatile a = 10;
0040100C mov dword ptr [esp],0Ah
int volatile *volatile pa = &a;
00401013 lea eax,[esp]
00401016 mov dword ptr [esp+8],eax
int volatile &volatile ra = a;
int volatile a1 = a;
0040101A mov ecx,dword ptr [esp]
0040101D mov dword ptr [esp+4],ecx
int volatile a2 = *pa;
00401021 mov edx,dword ptr [esp+8]
00401025 mov eax,dword ptr [edx]
00401027 mov dword ptr [esp+4],eax
int volatile a3 = ra;
0040102B mov ecx,dword ptr [esp]
0040102E mov dword ptr [esp+4],ecx
Здесь можно увидить, что хотя ссылка (ra) была явно объявлена как volatile, компилятор все равно при адресации использует переменную a, а сама переменная-ссылка "исчезла" за ненадобностью. Чего не произошло с указателем.
Не умножай количества сущностей сверх необходимого
Здравствуйте, igna, Вы писали:
I>Это... Кхм... Вы же не про заводится — не заводится писали, а про то, что память не выделяется: I>Я же утверждаю, что при передаче параметра по ссылке в общем случае память под ссылку выделяется (в стеке).
А если ложки не существует, то как она может оказаться в стеке ?
В стек кладется адрес объекта на который ссылка ссылается. Но не ссылка.
Здравствуйте, memorilik, Вы писали:
M>А если ложки не существует, то как она может оказаться в стеке ? M>В стек кладется адрес объекта на который ссылка ссылается. Но не ссылка.
Знаете что. Так конечно можно договориться и до того, что ссылка вообще никогда не требует памяти, в том числе, если она является членом. Не ссылка это мол, а адрес объекта и все тут. Можно. Но не нужно. Напоминаю, вы писали:
M>Т.е. я хотел сказать, что ссылка не является типом данных и под нее память не выделяется !
А стандарт допускает выделение памяти под ссылку:
It is unspecified whether or not a reference requires storage. (8.3.2/3)
И вот еще из Страуструпа:
In some cases, the compiler can optimize away a reference so that there is no object representing that reference at runtime. (5.5 References)
Как видите "unspecified" и "in some cases", так что в общем случае нельзя утверждать, что память под ссылку не выделяется.
Здравствуйте, memorilik, Вы писали:
M>ЗЫ. Я думаю если вы сможете обратиться к "чему-то" в "компьютере" не указав адрес это "чего-то" — нобелевская премия вам гарантирована !
Тривиально. Я, как автор гипотетического интерпретатора C++, могу сделать, чтобы ссылки представлялись текстовыми строками вида «член second переменной foo, объявленной во втором цикле for функции bar, вызванной из функции quux, вызванной из функции main». И в рантайме хранить значения переменных как std::map<std::string, boost::any>. Конечно, в конце концов неявно всё равно всё сведётся к адресам, но в представлении ссылок адресов не будет.
Здравствуйте, memorilik, Вы писали:
<skipped> M>Разница в том, что ссылка — это второе имя переменной. И на этапе компиляции компилятор заменяет ссылку нужным именем. Вот и все.
И чем тут будет заменена ссылка на этапе компиляции?
// 1void Foo( int& result )
{
///.....
}
// 2void Foo( int* p )
{
if (!p )return;
int& ref=*p;
//.....
}
Re[2]: В чём разница ссылки от указателя?
От:
Аноним
Дата:
05.05.06 07:36
Оценка:
Здравствуйте, LuciferMoscow, Вы писали:
LM>Здравствуйте, alex_ant, Вы писали:
_>>Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница? LM>1. Ссылка уже разименована. LM>2. Ссылка не мжет быть NULL LM>3. Указатель можно инициализировать много раз, ссылку — ровно один.
Добавлю:
4. Указатель — это lvalue, тоесть указатель сам имеет адрес, а ссылка адреса не имеет.
Здравствуйте, LuciferMoscow, Вы писали:
LM>2. Ссылка не мжет быть NULL
int val = 10;
int *p = &val;
// жил был указатель, тут его обнуляем...
p = NULL;
// а здесь получаем ссылку. увы ссылка нулевая и проверить уже никак не можем.int &ref = *p;
ref++;
P> int val = 10;
P> int *p = &val;
P> // жил был указатель, тут его обнуляем...
P> p = NULL;
P> // а здесь получаем ссылку. увы ссылка нулевая и проверить уже никак не можем.
P> int &ref = *p;
P> ref++;
P>
А здесь мы получаем не ссылку, а UB из-за разыменовывания нулевого указателя.
>Всем огромное спасибо! Воистину век живи, век учись...
только я бы сказал, что форум — не место для изучения азов: разница между ссылкой и указателем описана в любой книжке по с++
Здравствуйте, alex_ant, Вы писали:
_>Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
в C++ и указатели и ссылки косвенно ссылаются на обьект.
Два различия:
1. ссылка всегда обязана ссылаться на обьект, тогда как указатель может быть равен нулю.
2. после инициализации ссылки нельзя изменить то, куда она ссылается, а для указателей это возможно.
Здравствуйте, memorilik, Вы писали:
M>Здравствуйте, LuciferMoscow, Вы писали:
M>Вот что написано у Страуструпа (http://cclib.nsu.ru/projects/gnudocs/texts/cpptut.html)
Минус за размер файла, который находится по ссылке
M>2.3.10 M> Ссылка является другим именем объекта... Очевидным способом реализации ссылки является константный M>указатель...
Это не совсем то, что ты сказал.
M>2.4.6 M>...компилятор может несколькими путями M>воспользоваться тем, что объект является константой (конечно, в M>зависимости от того, насколько он сообразителен). Самое очевидное - M>это то, что для константы не требуется выделять память, поскольку M>компилятор знает ее значение.
Как это связано с предыдушим? M>Или я что-то не так понимаю ?
Здравствуйте, LuciferMoscow, Вы писали:
LM>Здравствуйте, memorilik, Вы писали:
M>>Здравствуйте, LuciferMoscow, Вы писали:
M>>Вот что написано у Страуструпа (http://cclib.nsu.ru/projects/gnudocs/texts/cpptut.html) LM>Минус за размер файла, который находится по ссылке
M>>2.3.10 M>> Ссылка является другим именем объекта... Очевидным способом реализации ссылки является константный M>>указатель... LM>Это не совсем то, что ты сказал.
M>>2.4.6 M>>...компилятор может несколькими путями M>>воспользоваться тем, что объект является константой (конечно, в M>>зависимости от того, насколько он сообразителен). Самое очевидное - M>>это то, что для константы не требуется выделять память, поскольку M>>компилятор знает ее значение. LM>Как это связано с предыдушим? M>>Или я что-то не так понимаю ?
ага, ты хочешь сказать, что ссылка это подмножество указателей. Да это так, но всё равно в этом случае ссылка отличается от указателя тем, что она является подмножеством, в то время как указатель понятие шире, а в чём шире, смотри мои различия.
Здравствуйте, Maxim_Popov, Вы писали:
M_P>Здравствуйте, alex_ant, Вы писали:
_>>Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
M_P>в C++ и указатели и ссылки косвенно ссылаются на обьект. M_P>Два различия: M_P>1. ссылка всегда обязана ссылаться на обьект, тогда как указатель может быть равен нулю. M_P>2. после инициализации ссылки нельзя изменить то, куда она ссылается, а для указателей это возможно.
все эти "различия" -- только синтаксис языка. в объектном коде и ссылка, и указатель -- это адрес. Соответственно, с ними можно делать все, что душе угодно:
int a = 0;
int &b = a; // b ссылается на aint c = 1;
__asm lea eax,[c]
__asm mov dword ptr [b],eax
/* теперь b ссылается на c */
b = 2; // c равно 2, а -- 0__asm mov dword ptr [b], 0
// теперь b равен нулю.
Здравствуйте, LuciferMoscow, Вы писали:
M>>Здравствуйте, LuciferMoscow, Вы писали:
M>>2.3.10 M>> Ссылка является другим именем объекта... Очевидным способом реализации ссылки является константный M>>указатель... LM>Это не совсем то, что ты сказал.
M>>2.4.6 M>>...компилятор может несколькими путями M>>воспользоваться тем, что объект является константой (конечно, в M>>зависимости от того, насколько он сообразителен). Самое очевидное - M>>это то, что для константы не требуется выделять память, поскольку M>>компилятор знает ее значение. LM>Как это связано с предыдушим?
Я сказал, что ссылка — второе имя переменной (у Страустрапа — другое имя объекта), так ? И что на этапе компиляции сама ссылка заменяется на адрес этой переменной.
Т.е. я хотел сказать, что ссылка не является типом данных и под нее память не выделяется !
Абзац про реализацию ссылки через константный указатель, как раз иллюстрирует конкретную реализацию этого механизма (через константый указатель).
Здравствуйте, igna, Вы писали:
M>>Т.е. я хотел сказать, что ссылка не является типом данных и под нее память не выделяется !
I>Вот про память в общем случае неверно.
Простите, господа, но у инженера есть главная заповедь "отвергаешь — предлагай !". Зачем выделять память под константу, если ее значение можно подставить на этапе компиляции ??? Мне это не понятно... Если здесь обсуждать сложно — xaliavka@mail.ru, я не против обсудить... Но тока обсуждать, а не критиковать !
Здравствуйте, memorilik, Вы писали:
M>Здравствуйте, igna, Вы писали:
M>>>Т.е. я хотел сказать, что ссылка не является типом данных и под нее память не выделяется !
I>>Вот про память в общем случае неверно.
M>Простите, господа, но у инженера есть главная заповедь "отвергаешь — предлагай !". Зачем выделять память под константу, если ее значение можно подставить на этапе компиляции ??? Мне это не понятно... Если здесь обсуждать сложно — xaliavka@mail.ru, я не против обсудить... Но тока обсуждать, а не критиковать !
Тебе тут втолковывают, что ты уцепился за частный случай
{
int x(0);
int& rx=x;
//тут память под rx действительно не нужна
// хотя это зависит от "разумности" компилятора
rx=::my_func_for_calc_the_x();
}
А есть другие случаи, типа:
class TC
{
public:
//ссылка x будет занимать место в стековой памяти
// ... если компилятор не встроит конструктор в точку вызова (я про inline)
TC(int& x):m_rx(x){;}
private:
int& m_rx;//вот тут память под ссылку тоже однозначно будет выделена
};//class TC
Кажись так
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Пока что (статистика за два года) ни один из кандидатов, с которыми я проводил интервью, не смог внятно объяснить, чем указатель отличается от ссылки. И ничего — многих из них взяли.
Мораль — эти знания не необходимы.
Здравствуйте, memorilik, Вы писали:
M>Простите, господа, но у инженера есть главная заповедь "отвергаешь — предлагай !". Зачем выделять память под константу, если ее значение можно подставить на этапе компиляции ???
Если под константой здесь подразумевается ссылка, то могу предложить совсем не экзотический пример передачи параметра по ссылке. Память под нее выделяется в стеке.
Здравствуйте, Vamp, Вы писали:
V>Пока что (статистика за два года) ни один из кандидатов, с которыми я проводил интервью, не смог внятно объяснить, чем указатель отличается от ссылки. И ничего — многих из них взяли.
Но те, которых взяли, по крайней мере не утверждали ничего ложного?
Re[2]: В чём разница ссылки от указателя?
От:
Аноним
Дата:
06.05.06 09:05
Оценка:
Здравствуйте, rg45, Вы писали:
Вот это непонятно:
R>4. Ссылка может обеспечвать время жизни временной переменной: пока жива ссылка, будет жива и временная переменная.
Значит ли это, что в таком коде автоматическая переменная будет жить после выхода из ф-ции:
CSomeClass & foo( void )
{
CSomeClass obj;
return obj; // <- Здесь не вызовется деструктор объекта obj? Или что я не так понимаю?
}
Здравствуйте, Vamp, Вы писали:
V>Пока что (статистика за два года) ни один из кандидатов, с которыми я проводил интервью, не смог внятно объяснить, чем указатель отличается от ссылки. И ничего — многих из них взяли. V>Мораль — эти знания не необходимы.
Интересно, ответ "указатель сможет заменить ссылку, а наоборот — нет" устроит?
Я вот тут (вчера) переделал
static int_type increment(volatile int_type& x)
на
static int_type increment(volatile int_type* x)
причем не потому, что может передаваться нулевой указатель (ссылка), а потому, что компилятор (BCB5), если мне врут мои глаза, посылает в лес попытки вызова increment с указателем другой (например на double) тип. А в случае ссылки — выдает предупреждение "создана временная переменная, результат будет потерян". Второй вариант меня напрягает.
Я сейчас комнату проветрю, может это у меня глюки пошли ....
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
" Аноним " <0@users.rsdn.ru> wrote in message news:1885913@news.rsdn.ru... > Здравствуйте, rg45, Вы писали: > > Вот это непонятно: > > R>4. Ссылка может обеспечвать время жизни временной переменной: пока жива ссылка, будет жива и временная переменная. > > Значит ли это, что в таком коде автоматическая переменная будет жить после выхода из ф-ции: > >
> CSomeClass & foo( void )
> {
> CSomeClass obj;
> return obj; // <- Здесь не вызовется деструктор объекта obj? Или что я не так понимаю?
> }
>
Все правильно, деструктор объекта вызовется, и так делать нельзя — в результате будет получена ссылка на уже несуществующий объект.
Я имел ввиду вот что:
CSomeClass foo( void ); //Результат функции - значение (не ссылка).
//...
CSomeClass& t = foo(); //Временный объект, возвращенный функцией будет жить до тех пор, пока жива ссылка
//...
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
КД>Интересно, ответ "указатель сможет заменить ссылку, а наоборот — нет" устроит?
Нет. Потому, что этот ответ не правилен в общем случае.
КД>Я вот тут (вчера) переделал... КД>...
Компилятор ведет себя неправильно. Так как ссылка не константная, он не может приявзывать ее к временному объекту.
Здравствуйте, Vamp, Вы писали:
КД>>Интересно, ответ "указатель сможет заменить ссылку, а наоборот — нет" устроит? V>Нет. Потому, что этот ответ не правилен в общем случае.
Пойду напьюсь с горя ...
КД>>Я вот тут (вчера) переделал... КД>>... V>Компилятор ведет себя неправильно. Так как ссылка не константная, он не может приявзывать ее к временному объекту.
Здравствуйте, memorilik, Вы писали:
<skipped> LM>>Как это связано с предыдушим? M>Я сказал, что ссылка — второе имя переменной (у Страустрапа — другое имя объекта), так ? И что на этапе компиляции сама ссылка заменяется на адрес этой переменной.
Цитирую Вас же
на этапе компиляции компилятор заменяет ссылку нужным именем
Это бред. Я приводил примеры, когда замените ссылку нужной переменной невозможно. M>Т.е. я хотел сказать, что ссылка не является типом данных и под нее память не выделяется !
А указатель уже ничего не весит(цитаем следующую(цитируюмую) сточку)? M>Абзац про реализацию ссылки через константный указатель, как раз иллюстрирует конкретную реализацию этого механизма (через константый указатель).
Здравствуйте, alex_ant, Вы писали:
_>Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
Меня хватило, прочесть всё что тут наотвечали, так что, прошу не считать мои слова плагиатом, а выражением собирательного из чужих высказываний, прочитаных книг и собственных мыслей. (ОТ СКАЗАНУЛ ТО!!! :-) ).
Итак, если у нас имеется объект A, то:
декларировать PA как указатель на A, значит создать объект типа "адрес в памяти" и значением равным адресу размещения в памяти объекта A.
декларировать RA как ссылку на A, значит создать объект типа A и с адресом равным адресу размещения объекта A.
Вы можете меня придушить, сказав что в случае со ссылкой ничё не создаётся, а я вам возражу -- СОЗДАЁТСЯ. Да в памяти мож ничё и не создаётся, это при реализации, а мы то говорим о языке!!! Тут ж дело в абстракции, нам только говориться что выполнение такого-то оператора, приведёт к таким-то результатам, а как это будет сделано нам никто не говорит!!!
В нашем случае (с указателями и ссылками) нам говорится следующее, задекларировали ссылку, задекларировали указатель -- получили объекты со следующими свойствами:
&A == &RA == PA
A == RA == *PA
И из этого конечно следует, что изменение значения RA приведёт к одновременному изменению значения A, и что если мы что-то запишем в память по адресу PA, то мы изменим значение A.
Вот весёленький примерчик:
// скомпилировано на VC6#include <windows.h>
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Засуньте в Watch g, gl, gh а заодно и &g, &gl, &gh и многое увидите.int g = 0;
unsigned short &gl = reinterpret_cast<unsigned short *>(&g)[0];
unsigned short &gh = reinterpret_cast<unsigned short *>(&g)[1];
gl++;
gh++;
g = ::GetTickCount();
g /= 3;
g *= 5;
return 0;
}
Теперь про передачу указателя и ссылки: и там и там в реализации передаётся адрес, только в случае со ссылкой NULL (или недостоверный указатель) не передаш.
Вот пример, сие доказывающий:
Вы можете сказать, что компилятор вообще может не использовать параметр по ссылке, а напрямую переменную, передаваемую в процедуру. Я считаю, что это козни оптимизатора (т.е. опять вопрос реализации, который нас не должен волновать), засуньте функции byref и byptr в Dll и всё будет нормально.
Нет, я не говорю что знание реализации это нехорошо -- это хорошо, это помогает писать более быстрый код и лучше отлавливать и понимать ошибки. Просто нинадо смешивать философию (или предметную область) реализации и философию собсно языка.
Тут кто-то сказал что указатели не нужны... Так если б они были ненужны, их бы никто не использовал. Вот то что указатели вредны -- я могу согласиться. А вредны они, потомучто дают прямой доступ к памяти, а это бооольшое поле для обхода множества ограничений языка т.е. наклёпывания страшных, фатальных и трудноуловимых ошибок.
2pullover:
int val = 10;
int *p = &val;
// Оператор "*" разименования указателя, даёт rvalue, а у rvalue нельзя взять адрес,
// т.е. низя сделать объект с адресом таким же как у объекта у которого адреса нет,
// так что IMHO факт того, что такой опенратор скомпилился, является BUG'ом
// компилятора, а не языка.int &ref = *p;
Вот такое моё мнение, MHO (от IMHO) точнее. Жду конструктивную критику! ;)
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
ZAM>Тут кто-то сказал что указатели не нужны... Так если б они были ненужны, их бы никто не использовал. Вот то что указатели вредны -- я могу согласиться. А вредны они, потомучто дают прямой доступ к памяти, а это бооольшое поле для обхода множества ограничений языка т.е. наклёпывания страшных, фатальных и трудноуловимых ошибок.
В свое время, именно работа с указателями выделялась как одно из самых мощных, ключевых средств языка C...
Здравствуйте, rg45, Вы писали:
R>Я имел ввиду вот что: R>
CSomeClass foo( void ); //Результат функции - значение (не ссылка).
//...
CSomeClass& t = foo(); //Временный объект, возвращенный функцией будет жить до тех пор, пока жива ссылка
//...
А там const не потерялось? /Za рулит. И даже если компилятор позволяет писать такие гадости, то надеяться на 12.2/5 уже не приходится.
Ссылки — внутриязыковое средство адресного (косвенного, именного) обращения к данным. Примечание — термин "адресное обращение" используется не в значении "адрес памяти".
Ссылки — суть более высокоуровневая абстракция указателей.
Ссылки введены для повышения эффективности, при использовании указателей-ссылок еще на этапе программирования и проектирования. Для этого для ссылок введены дополнительные ограничения.
Указатель является реальным hardware/software отображаемым объектом, переменной, содержащим адрес. Это значит, что под объект типа указатель будет распределена какая-либо память (например регистровая). Указатели имеют linkage.
Ссылка же предоставляется объектом только в случае невозможности абстракции ее как альтернативного "имени" объекта. В этом случае ссылки мэпятся на указатели. Ссылки не имеют linkage.
Здравствуйте, A.R., Вы писали:
ZAM>>Тут кто-то сказал что указатели не нужны... Так если б они были ненужны, их бы никто не использовал. Вот то что указатели вредны -- я могу согласиться. А вредны они, потомучто дают прямой доступ к памяти, а это бооольшое поле для обхода множества ограничений языка т.е. наклёпывания страшных, фатальных и трудноуловимых ошибок.
AR>В свое время, именно работа с указателями выделялась как одно из самых мощных, ключевых средств языка C...
В своё время, атомные электростанции считались самым безопасным способом вырабатывания электроэнергии...
И, кстати, я не сказал что пользоваться указателями нельзя вообще... как впрочем и атомными электростанциями неперестали пользоваться! ;)
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Здравствуйте, ZAMUNDA, Вы писали:
ZAM>2pullover: ZAM>
ZAM> int val = 10;
ZAM> int *p = &val;
ZAM> // Оператор "*" разименования указателя, даёт rvalue, а у rvalue нельзя взять адрес,
ZAM> // т.е. низя сделать объект с адресом таким же как у объекта у которого адреса нет,
ZAM> // так что IMHO факт того, что такой опенратор скомпилился, является BUG'ом
ZAM> // компилятора, а не языка.
ZAM> int &ref = *p;
ZAM>
А как же, например, такая запись: *p = 1; ? Оператор * как раз имеет тип lvalue. Если есть сомнения, смотри (5.3.1/1).
Здравствуйте, A.R., Вы писали:
AR>Указатель является реальным hardware/software отображаемым объектом, переменной, содержащим адрес. Это значит, что под объект типа указатель будет распределена какая-либо память (например регистровая). Указатели имеют linkage.
Указатели могут не иметь связывания:
int main( void )
{
int * test;
}
AR>Ссылка же предоставляется объектом только в случае невозможности абстракции ее как альтернативного "имени" объекта. В этом случае ссылки мэпятся на указатели. Ссылки не имеют linkage.
Ссылки могут имеют связывание (3.5/2-4). В частности, такая программа является корректной:
tu1.cpp
int io( 10 );
int & i( io );
tu2.cpp
#include <iostream>
extern int & i;
int main( void )
{
::std::cout << i;
}
Однако с остальными аргументами я полностью согласен . Хотелось бы только дополнить.
Я думаю, рассмотрение ссылок и указателей с точки зрения их различий с указателями не является до конца корректным и адекватным. Ссылки и указатели — это абсолютно разные сущности языка с различным синтаксисом и семантикой инициализации и использования, так же, как, например, указатели и арефметические типы.
Если АТ действительно не знаком со ссылками, то, возможно, действительно имеет смысл рассматривать их как аналог уже знакомых сущностей (естественно, учитывая, что такая модель на точность не претендует). В таком случае, я бы указал на двойственную природу ссылок.
Ссылка может быть похожа на указатель. Синтаксически, т.к. и ссылка, и указатель являются compound type и семантически, т.к. и ссылка и указатель — средства непрямого обращения к объекту, возможно, неименованному.
Ссылка может быть похожа на имя объекта. Синтаксически, т.к. обращение к ассоциированному объекту осуществляется посредствам только Lvalue-to-rvalue conversion и семантически, т.к. ссылка может быть синонимом существующего имени, а так же не является объектом и может не требовать storage.
Хорошо, если такая модель поможет понять суть вопроса. Однако для более подробного знакомства необходимо рассматривать ссылку как отдельную сущность, безотносительно к указателю и имени переменной. Тут, скорее, поможет чтение FAQ-ов и другой литературы или поиск по форуму, без конкретных вопросов врядли дискуссия будет конструктивной.
Здравствуйте, memorilik, Вы писали:
LM>>Это бред. Я приводил примеры, когда замените ссылку нужной переменной невозможно.
M>К сожелению (а может и к счастью) это не бред, а полная правда.
Ранее было также:
M>Т.е. я хотел сказать, что ссылка не является типом данных и под нее память не выделяется !
Здравствуйте, igna, Вы писали:
I>В невыделение памяти вы еще верите?
Хочу сделать одно замечание: данные топик называется "В чем разница ссылки от указателя", так вот, указатель — тип данных, а ссылка — второе имя объекта (переменной). Ссылка не является объектом. Это насчет темы вопроса по существу.
Насчет памяти — вопрос второй, но я пока что по нему мнения не изменил. Т.к. класс — это не просто тип данных, то для того чтобы ответить на этот вопрос надо знать реализацию таблиц переменных класса, таблиц семантических разборов компилятора и т.д и т.п.. К сожелению компиляторами я занимался давольно давно и не очень глубоко, поэтому точно не помню где и что лежит. Если кто-то меня поправит, покажет что память под ссылки выделяется — буду только признателен. Только сразу говорю — sizeof(...) — это не аргумент.
Здравствуйте, memorilik, Вы писали:
M>Здравствуйте, igna, Вы писали:
I>>В невыделение памяти вы еще верите?
M>Хочу сделать одно замечание: данные топик называется "В чем разница ссылки от указателя", так вот, указатель — тип данных, а ссылка — второе имя объекта (переменной). Ссылка не является объектом. Это насчет темы вопроса по существу.
Ну вы люди и даете... угля мелкого, но много !
А как можно к чему-то обратиться не зная его адреса ???????????????????????? Подскажите, плиз !!!
Объясняю. На этапе компиляции компилятор проводит семантический разбор программы. Создает, например, таблицу переменных в которой находиться соответствие переменной и каких-то свойств, строит деревья разбора и т.д. Так вот. Для ссылки переменная ни где не заводиться ! Вместо ссылки подставляется адрес переменной ! И, в вашем случае, именно он (а не какая-то ссылка или ее адрес) кладется в стек ! Тут-то все понятно ?
Говорю сразу что это схема — сильно(очень сильно) упрощенная ! Для классов и вовсе все сложнее !
ЗЫ. Я думаю если вы сможете обратиться к "чему-то" в "компьютере" не указав адрес это "чего-то" — нобелевская премия вам гарантирована !
Здравствуйте, memorilik, Вы писали:
M>Объясняю. На этапе компиляции компилятор проводит семантический разбор программы. Создает, например, таблицу переменных в которой находиться соответствие переменной и каких-то свойств, строит деревья разбора и т.д. Так вот. Для ссылки переменная ни где не заводиться ! Вместо ссылки подставляется адрес переменной ! И, в вашем случае, именно он (а не какая-то ссылка или ее адрес) кладется в стек ! Тут-то все понятно ?
Это... Кхм... Вы же не про заводится — не заводится писали, а про то, что память не выделяется:
M>Т.е. я хотел сказать, что ссылка не является типом данных и под нее память не выделяется !
Я же утверждаю, что при передаче параметра по ссылке в общем случае память под ссылку выделяется (в стеке).
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>В стек в языке С++ ничего не кладется. Потому что в С++ нет никакого аппаратного стека.
А в языке ассемблер какой стек ? Аппаратный ? Или, перефразирую одну шутку, — "язык С++ намного эффективнее ассемблера потому, что выполняет многие команды минуя процессор" ? Стек, он и в Африке — стек. И аппаратный он бывает тока на специализированном железе.
PD>А в рабочей программе туда кладется в обоих случаях адрес переменной. А адрес — такого понятия в С++ тоже нет.
Куда — туда ? В стек ? И адрес — такое понятие в С++ есть. Адрес — это _значение_ указателя. Можете его даже распечатать, например .
PD>А есть ссылки и указатели.
"memorilik" <54054@users.rsdn.ru> wrote in message news:1885476@news.rsdn.ru... > > Т.е. я хотел сказать, что ссылка не является типом данных и под нее память не выделяется !
То, что это не так, можно продемонстрировать следующем фрагментом, который Комо компилирует без ошибок:
struct Pointers{
int *m1,*m2,*m3,*m4;
};
struct References{
int &m1,&m2,&m3,&m4;
References();
};
int test[sizeof(References) == sizeof(Pointers)];
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
Доброго времени суток всем. Почитал диалоги на форуме, да впринципе почти все уже сказали и
выяснили, что есть ссылка что есть указатель, остается только просуммировать и подытожить.
Тем не менее были и грубые ошибки типа:
class TC
{
public:
//ссылка x будет занимать место в стековой памяти
// ... если компилятор не встроит конструктор в точку вызова (я про inline)
TC(int& x):m_rx(x){;}
private:
int& m_rx;//вот тут память под ссылку тоже однозначно будет выделена
};//class TC
Этот пример даже не скомпилируется, потому что ссылка инициализируется сразу.
Но это не суть важно важно то что в споре рождается истина а истина — новое
знание, другое дело имеет это знание практическое применение.
ссылки как оказывается имеют ограниченную область применения. Об этом позже.
Вопрос был такой:
"Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между
ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я
не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали.
Так в чём же разница?"
Здесь можно подойти к ответу с двух основных точек зрения:
— как, зачем и когда использовать указатели и ссылки в программе, каковы их сходства и отличия;
— как компилятор оптимизирует представление этих объектов в машинном коде (напр исп памяти);
Рассмотрим по порядку.
Указатели были введены в язык С для реализации возможностей работы с памятью в частности с кучей,
для передачи параметров из функций, для поддержки механизма обратного вызова (указатель на функцию).
Кроме того указатели это встроенный тип данных с которым можно производить некоторые арифметические
операции, присваивание, разыменование, приведение.
Ссылки же были введены в язык С++ как средство частичной замены функции указателей при передаче параметров
из функций. Ссылка это псевдоним имени переменной не более того. И ссылка это не встроенный тип данных в
том смысле, что ее можно использовать как все другие типы.
Главный идеолог языка С++ Бьерн Страуструп в своей общеизвестной книге "Язык программирования С++"
отмечает следующее (цитирую):
1) Ни один оператор не выполняет действий над ссылкой;
2) Инициализация ссылки отличается от присваивания ей значения;
3) Реализована ссылка как константный указатель при каждом использовании которого происходит разыменование;
4) В некоторых случаях компилятор может оптимизировать ссылку таким образом, что во время выполнения вообще не
будет существовать объекта представляющего ссылку;
Вот мы и подошли ко второй точке зрения на обсуждаемые объекты. Это во многом интересный вопрос и в тоже
время бесполезный. Ну что толку с того что под ссылки компилятор не резервирует памяти, или ничего не
заталкивает в стек? А если выделяет, то много ли памяти занимают эти объекты. Нужно понимать что цель ссылок
не в том чтобы экономить память (или что-то другое) путем новых изобретенных синтаксических конструкций языка.
Но все же интересно, как представляются в памяти ссылки если они вообще представляются. Бьерн говорит об
оптимизации компилятором кода, но не исключает возможности размещения ссылок в памяти.
Что ж лучший ответ на этот вопрос даст сам компилятор. Обратимся к нему. Ниже я привожу код на С++ который
мы проанализируем после дизасемблирования. Цель посмотреть что представляют собой ссылки при передаче
значений параметров из функций сравнить это же с указателями. Как ссылки определяются в программе и что этому
соответствует в машинном коде. Пример создавался и тестился в среде VS2005, (пример с классами и прочими
конструкциями только усложнит анализ) все ключи МАKE-раздела компиляции и сборки оставлены по умолчанию.
Каждый может проверить это собственноручно. Итак:
Что же здесь мы видим? Для определения float& l3=i3;
в строках 15 и 16 ясно видно что никакого места
под ссылку не выделяется, (если конечно вспомним что делает команда lea)
А вот далее интереснее
Для конструкции const int& li2 = 10;
в строке 17 используется память для
хранения константы. А далее в строке 18 получаем смещение этой ячейки,
а встроке 19 (внимание) используется ячейка памяти для хранения ссылки
на константу. Причем рамер ее как видно 32 бита. Наталкивает на мысль
что это ни что иное как указатель, который нельзя поменять. Конечно
кто-то может поспорить что это некорректное определение константы, но это
работает и Бьерн приводит такой же пример задания ссылки.
Далее анализируя вызовы функций приходим к выводу что они абсолютно идентичны
для указателей и для ссылок. Для передачи параметров из функций используется стек.
Очевидно не так ли.
Что же мы имеем в итоге. Оказывается память под ссылку может как выделяться так и не
выделяться. Это зависит от написанного кода. В общем случае конечно.
Есть еще такое как оптимизация и около 200 различных С компиляторов. И каждый
может по своему это оптимизировать.
Но передачей параметров ясно, что стек используется.
Кроме оптимизации и определенно написанного исходника есть еще стандарт, но это
уже тема отдельного разговора. Отмечу только то что в компиляторах
реализованных по стандарту ISO/IEC 14882, ссылки задаются и работают корректно,
так что приведенные вначале примеры вообще не скомпилируются, а пример со структурой
в которой ссылки, компилятор VS2005 выведет вот что:
Error 1 error C2327: 'STR::a' : is not a type name, static, or enumerator
c:\documents and settings\aan\my documents\visual studio 2005\projects\links\links\links.cpp 10
Error 2 error C2065: 'a' : undeclared identifier
c:\documents and settings\aan\my documents\visual studio 2005\projects\links\links\links.cpp 10
Error 3 error C2864: 'STR::la' : only static const integral data members can be initialized within a class
С:\documents and settings\aan\my documents\visual studio 2005\projects\links\links\links.cpp 10
Error 4 error C2327: 'STR::b' : is not a type name, static, or enumerator
c:\documents and settings\aan\my documents\visual studio 2005\projects\links\links\links.cpp 11
Error 5 error C2065: 'b' : undeclared identifier
c:\documents and settings\aan\my documents\visual studio 2005\projects\links\links\links.cpp 11
Error 6 error C2864: 'STR::lb' : only static const integral data members can be initialized within a class
c:\documents and settings\aan\my documents\visual studio 2005\projects\links\links\links.cpp 11
Так что если у кого-то или где-то в каком-то компиляторе такое задание возможно, значит это несоответствие
стандартам или свой собственный стандарт (что вполне может быть).
В заключении отмечу, что ни один C++ компилятор на 100% не соответствует ни одному стандарту, более того
часто отступают от него, добавляют свои конструкции, и майкросовтовский тут не исключение.
S>class TC
S>{
S> public:
S> //ссылка x будет занимать место в стековой памяти
S> // ... если компилятор не встроит конструктор в точку вызова (я про inline)
S> TC(int& x):m_rx(x){;}
S> private:
S> int& m_rx;//вот тут память под ссылку тоже однозначно будет выделена
S>};//class TC
Здравствуйте, igna, Вы писали:
I>Здравствуйте, shrkn, Вы писали:
I>
S>>class TC
S>>{
S>> public:
S>> //ссылка x будет занимать место в стековой памяти
S>> // ... если компилятор не встроит конструктор в точку вызова (я про inline)
S>> TC(int& x):m_rx(x){;}
S>> private:
S>> int& m_rx;//вот тут память под ссылку тоже однозначно будет выделена
S>>};//class TC
I>
Да согласен этот пример откомпилиться, вполне, даже на VS2005, я что-то наверно не досмотрел
когда проверял, так что извиняйте. Но про ссылки и выделение памяти все так же в силе.
В классах конструктор может выполнять функции инициализации ссылок.
S>class TC
S>{
S> public:
S> //ссылка x будет занимать место в стековой памяти
S> // ... если компилятор не встроит конструктор в точку вызова (я про inline)
S> TC(int& x):m_rx(x){;}
S> private:
S> int& m_rx;//вот тут память под ссылку тоже однозначно будет выделена
S>};//class TC
S>
S> Этот пример даже не скомпилируется, потому что ссылка инициализируется сразу.
vis c++.net 7.1 компилиться за милую душу..
может это я что то не так делаю?
Здравствуйте, alex_ant, Вы писали:
_>Недавно один товарищ на мой вопрос по языку С++ заметил «У… батенька мы даже не знаем разницы между ссылкой и указателем! Темнота!..» Для меня, честно говоря, это оказалось откровением. В литературе я не встречал чёткого разграничения этих понятий и воспринимал их как синонимы. Поиски ничего не дали. Так в чём же разница?
Глюк случился..
Вместо моей мессаги отправилась какая-то левая.
Тем не менее, повторю вопрос.
Я долгое время работал только на бейсике, паскале, знал что такое переменная, константа и радовался жизни.
Теперь же, изучая C++, меня подвергли в шок такие понятия как ссылка, указатель. Я пытался понять что это такое, ища ответ в трех разных учебниках, но так и не понял (после паскаля, бейсика,мне сложно все это понять).
Поясните плиз или подскажите, где можно объяняются эти понятия человеческим, нормальным языком.