В Java работа с объектами осуществляется через reference-type переменные. В C# для ускорения работы придумано хитрое средство под названием boxing/unboxing — упрятывает value-type в reference-type и обратно. И в том и в другом языке pointer-type если и есть, то этим термином названа "низкая" unsafe работа с адресами. Хотелось бы восстановить доброе имя pointer-type. Дело в том, что, например, в оберонах есть все три сорта типов value-type, reference-type и pointer-type, и все они совершенно безопасны (safe) и управляются сборщиком мусора.
TYPE
ValueType = RECORD
a: PointerType;
b: ReferenceType;
END;
ReferenceType = POINTER TO RECORD
a: PointerType;
b: ReferenceType;
c: ValueType;
END;
PointerType = POINTER TO ValueType;
То есть, никакие хитрости boxing/unboxing не нужны если есть обыкновенный безопасный pointer-type управляемый сборщиком мусора. Отсюда нет дискредитации термина УКАЗАТЕЛЬ как чего-то низменного и недостойного safe кода. Указатель — это хорошо и не более опасно чем reference-type.
P.S.
Другое дело, что не надо путать два разных понятия УКАЗАТЕЛЬ и АДРЕС. Указатель — это одно, а адрес, адресное пространство и адресная арифметика — это совершенно другое.
СГ>TYPE
СГ> ValueType = RECORD
СГ> a: PointerType;
СГ> b: ReferenceType;
СГ> END;
СГ> ReferenceType = POINTER TO RECORD
СГ> a: PointerType;
СГ> b: ReferenceType;
СГ> c: ValueType;
СГ> END;
СГ> PointerType = POINTER TO ValueType;
СГ>
Из этого примера совершенно неясно, в чем семантическое отличие между PointerType и ReferenceType. Ну и если мы уж зашла речь об оберонах, то грех не вспомнить про untraced поинтеры, которые как раз небезопасны и сборщиком мусора не собираются. СГ>То есть, никакие хитрости boxing/unboxing не нужны если есть обыкновенный безопасный pointer-type управляемый сборщиком мусора. Отсюда нет дискредитации термина УКАЗАТЕЛЬ как чего-то низменного и недостойного safe кода. Указатель — это хорошо и не более опасно чем reference-type.
От того, что ты назвал поинтером то, что в других языках называется ссылкой, её суть никак не изменилась. Boxing/Unboxing нужен не из-за того, что с указателями что-то не так.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AndrewVK, Вы писали:
AVK>Простой вопрос. Псевдокод AVK>
AVK>int* GetSomeData()
AVK>{
AVK> int i = 3;
AVK> return &i;
AVK>}
AVK>void Main()
AVK>{
AVK> int* ip = GetSomeData();
AVK> // 1
AVK>}
AVK>
AVK>Куда в 1 будет указывать указатель ip?
Простой ответ, так делать нельзя:
Другое дело, что не надо путать два разных понятия УКАЗАТЕЛЬ и АДРЕС. Указатель — это одно, а адрес, адресное пространство и адресная арифметика — это совершенно другое.
Операция "&" — есть операция взятия адреса, таким образом, в Си/Си++ указатели и адреса это одно и тоже.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Сергей Губанов, Вы писали:
СГ>>
СГ>>TYPE
СГ>> ValueType = RECORD
СГ>> a: PointerType;
СГ>> b: ReferenceType;
СГ>> END;
СГ>> ReferenceType = POINTER TO RECORD
СГ>> a: PointerType;
СГ>> b: ReferenceType;
СГ>> c: ValueType;
СГ>> END;
СГ>> PointerType = POINTER TO ValueType;
СГ>>
S>Из этого примера совершенно неясно, в чем семантическое отличие между PointerType и ReferenceType.
Например, если отдельно объявлен ValueType и PointerType, то, например, можно и два разных массива сделать массив значений (можно размещать на стеке) или массив указателей (динамическое размещение). А если объявлен только ReferenceType — то только с указателями можно работать, то есть только динамически размещать с помощью NEW, а на стеке нельзя.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Простой ответ, так делать нельзя:
. А смысл тогда в таких поинтерах?
СГ>
СГ>Другое дело, что не надо путать два разных понятия УКАЗАТЕЛЬ и АДРЕС. Указатель — это одно, а адрес, адресное пространство и адресная арифметика — это совершенно другое.
СГ>Операция "&" — есть операция взятия адреса, таким образом, в Си/Си++ указатели и адреса это одно и тоже.
Я же написал — ПСЕВДОКОД, а не С/С++. Воспринимай эту операцию как операцию получения указателя по значению. Никакой адресной арифметики.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Простой ответ, так делать нельзя: СГ>
СГ>Другое дело, что не надо путать два разных понятия УКАЗАТЕЛЬ и АДРЕС. Указатель — это одно, а адрес, адресное пространство и адресная арифметика — это совершенно другое.
СГ>Операция "&" — есть операция взятия адреса, таким образом, в Си/Си++ указатели и адреса это одно и тоже.
ладно перепишу
int& GetSomeData()
{
int i = 3;
return i;
}
void Main()
{
int& ip = GetSomeData();
// 1
}
вопрос тотже.
... << RSDN@Home 1.1.4 rev. 185 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, AndrewVK, Вы писали:
AVK>. А смысл тогда в таких поинтерах?
В том что отдельно объявлен тип-значение и отдельно объявлен указательный-тип. Стало быть, Вы можете на свое усмотрение создавать переменные и на стеке и в куче. А с ссылочным-типом Вы можете располагать объекты только в куче, а на стеке не можете.
Здравствуйте, Сергей Губанов, Вы писали:
WH>>ладно перепишу
СГ>Все равно нельзя — ссылка из Си/Си++ очень переочень сильно замаскированный указатель, который все равно адрес.
Да при чем здесь С++ то? Хорошо, переформулирую на русский язык — куда будет указывать указатель после выхода из процедуры, если до выхода он указывал на локальную переменную value-типа?
Здравствуйте, Сергей Губанов, Вы писали:
AVK>>. А смысл тогда в таких поинтерах?
СГ>В том что отдельно объявлен тип-значение и отдельно объявлен указательный-тип. Стало быть, Вы можете на свое усмотрение создавать переменные и на стеке и в куче. А с ссылочным-типом Вы можете располагать объекты только в куче, а на стеке не можете.
Ага, здорово. Вот только в дотнете с боксингом оно как то лучше выходит — я могу создавать ссылку на value-тип вне зависимости от того где он находится — в куче или в стеке. В чем кайф такого коцаного указателя я так и не понял. Для чего его использовать?
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Сергей Губанов, Вы писали:
WH>>>ладно перепишу
СГ>>Все равно нельзя — ссылка из Си/Си++ очень переочень сильно замаскированный указатель, который все равно адрес.
AVK>Да при чем здесь С++ то? Хорошо, переформулирую на русский язык — куда будет указывать указатель после выхода из процедуры, если до выхода он указывал на локальную переменную value-типа?
Не существует способа заставить указывать указатель на размещенную на стеке локальную переменную value-типа. Переменные указательных типов создаются с помощью NEW, переменные value-типа создаются на стеке. Друг в друга уже размещенные в памяти переменные (заметьте, двух разных типов) по волшебству не превращаются. Можно лишь копировать содержимое одной в содержимое другой, т.к. содержимое у них устроено одинаково.
Здравствуйте, Сергей Губанов, Вы писали:
AVK>> ...Для чего его использовать?
СГ>Ё-ё-ё-о-о-у-у-у.
СГ>Указатель на объект используют для того чтобы размещать объект в динамической памяти.
Т.е. если нет указателей, то разместить объект в динамической памяти нельзя? Йоуууу!!!
Если я правильно уловил идею...
Имеются три квалификатора типа: "динамик", "аргумент-ссылка", "значение".
"Динамик" означает, что объект создан на куче, оператором new.
"Значение" — объект создан не оператором new. (Это или локальная переменная, или член-данное, или элемент массива значений).
При этом допускается конверсия
динамик|значение -> аргумент-ссылка
динамик|аргумент-ссылка -> значение (создаётся копия)
динамик|аргумент-ссылка|значение -> динамик (создаётся копия; только явным способом, вызов new)
То есть, снять квалификатор "динамик" можно, а повесить — нельзя.
В этом случае, оказывается невозможным возвращать указатели на временные объекты.
Одновременно, мы пожертвовали возможностью создавать связи с элементами структур/массивов.
Впрочем, мы можем обойтись: если известно, что некий элемент структуры (массива/записи) будет отдан на сторону, то объявим (и создадим) его динамическим.
Обратите внимание: квалификатор "динамик" можно давать любым типам, в том числе примитивным.
Задача боксинга переносится на стадию дизайна: хочешь отдавать что-то на сторону — изволь объявить.
Заодно упрощается сборка мусора: нет нужды отслеживать внешние указатели на элементы структуры.
Ещё один момент: такая схема усложняет реализацию множественного наследования.
Либо интерфейс / базовый подобъект не может быть квалифицирован как динамик, либо требуется прокси-объект типа "интерфейс" с квалификатором "динамик", держащий ссылку на объект целиком. Причём сам объект должен быть только динамическим (ведь ссылки на не-динамики заначивать невозможно).
Здравствуйте, Сергей Губанов, Вы писали:
AVK>>Т.е. если нет указателей, то разместить объект в динамической памяти нельзя? Йоуууу!!!
СГ>Да, нельзя. А что, знаете способ?
Здравствуйте, Кодт, Вы писали:
К>Если я правильно уловил идею...
Есть еще парочка уточнений.
Например, в Component Pascal указатели могут быть не на любые типы, а только на RECORD или на ARRAY (Кстати, просто обычный ARRAY — это value-type, динамический ARRAY уже reference-type, но на обычный ARRAY можно объявить указатель и получить pointer-type).
TYPE
ValueArray = ARRAY 10, 10 OF INTEGER;
(* Матрица 10*10 размещаемая на стеке *)
ReferenceArray = ARRAY OF AARAY OF INTEGER;
(* Двумерный динамический массив, точнее одномерный массив одномерных массивов *)
PointerArray = POINTER TO ARRAY 10, 10 OF INTEGER;
(* Матрица 10*10 размещаемая в динамической памяти *)
Что касается рассширения типов (то бишь, наследования), то тут квалификатор "POINTER TO", как бы, игнорируются, то есть то что базовый тип был ссылочным не мешает рассширение типа сделать типом-значением
Base = POINTER TO EXTENSIBLE RECORD(* ... *)END;
Derived = RECORD (Base)
(* ... *)END;
Или наоборот:
Base = EXTENSIBLE RECORD(* ... *)END;
Derived = POINTER TO RECORD (Base)
(* ... *)END;
"POINTER TO" — для расширения типов не имеет значения.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Сергей Губанов, Вы писали:
AVK>>>Т.е. если нет указателей, то разместить объект в динамической памяти нельзя? Йоуууу!!!
СГ>>Да, нельзя. А что, знаете способ?
AVK>Ага. Например тот что использует джава и дотнет.
Java и C# как раз и используют то что в терминологии оберонов называется POINTER TO RECORD, то есть refernce-type.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Java и C# как раз и используют то что в терминологии оберонов называется POINTER TO RECORD, то есть refernce-type.