Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.82/56: Рейтинг темы: голосов - 56, средняя оценка - 4.82
8 / 9 / 1
Регистрация: 21.08.2012
Сообщений: 34
1

Value type и reference type

19.02.2013, 13:53. Показов 11311. Ответов 29
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет!
После прочтения некоторых книг по .NET до сих пор меня мучат несколько вопросов.
В некоторых книгах, говоря про отличие типов значения от ссылочных типов, утверждается, что основное их отличие - это то, что типы значения хранятся в стеке. Ссылочные типы так: сама ссылка в стеке и ссылается на область памяти в куче. Но что будет, если у нас такой код:
C#
1
int[] array = new array[10];
?
Так как массив - это ссылочный тип, то получается, что 10 элементов типа int хранятся все-таки в куче. Я правильно понимаю?
А как хранятся элементы value типа в коллекциях, например, в List? Тоже ведь в куче? А в List<T> например?

И последнее. В приведенном выше коде будет производится операция упаковки, или она производится только в том случае, когда требуется приведение к типу object?

Извините за сумбурность, просто много вопросов накопилось, на которые разные книги дают противоречивые ответы.
Заранее благодраю за ответы.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.02.2013, 13:53
Ответы с готовыми решениями:

Особенности хранения value type и reference type
Всем известно, что значимые типы хранятся в стеке(смутно представляю, что он из себя представляет,...

Интересная ситуация с reference type
class Program { public Program(int o) { ...

Ошибка в программе: The non-generic type 'ArrayList' cannot be used with type arguments
Помогите исправить ошибку Compilation error solution.cs(12,38): error CS0308: The non-generic type...

Ошибка CDO:Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Interop.Outlook.MailItem'
Здаствуйте у меня такая проблема, я получаю сообщения с Outlook'а путем простейших махинаций, когда...

29
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
19.02.2013, 17:11 2
Цитата Сообщение от Fmamedov Посмотреть сообщение
В некоторых книгах, говоря про отличие типов значения от ссылочных типов, утверждается, что основное их отличие - это то, что типы значения хранятся в стеке.
Плохие это книги.
Основное отличие в том, что при присваивании переменной и передачи между методами value типы копируются полностью, а ссылочные типы - только ссылка.

Цитата Сообщение от Fmamedov Посмотреть сообщение
Так как массив - это ссылочный тип, то получается, что 10 элементов типа int хранятся все-таки в куче. Я правильно понимаю?
Да.

Цитата Сообщение от Fmamedov Посмотреть сообщение
А как хранятся элементы value типа в коллекциях, например, в List? Тоже ведь в куче? А в List<T> например?
Точно так же, потому что лист в кишках использует обычный массив.

Цитата Сообщение от Fmamedov Посмотреть сообщение
В приведенном выше коде будет производится операция упаковки, или она производится только в том случае, когда требуется приведение к типу object?
Второй вариант.
0
136 / 138 / 18
Регистрация: 26.07.2010
Сообщений: 911
19.02.2013, 17:27 3
Цитата Сообщение от Fmamedov Посмотреть сообщение
И последнее. В приведенном выше коде будет производится операция упаковки?
Упаковки не будет, хотя ваши структуры и будут хранится в куче.

Упаковки не будет так же и тогда, когда вы инициализируете поле класса которое является структурой. Хотя поле вашего класса тоже будет хранится в куче.
C#
1
2
3
4
class MyClass
{
   int i = 5; //упаковки не будет
}
Цитата Сообщение от Fmamedov Посмотреть сообщение
когда требуется приведение к типу object?
Плюс еще если вы будете приводить структуру к интерфейсному типу.
Интерфейсная переменная всегда является ссылочным типом.
0
8 / 9 / 1
Регистрация: 21.08.2012
Сообщений: 34
19.02.2013, 18:02  [ТС] 4
Всем спасибо большое за ответы. Все для себя прояснил.
0
Темная сторона .Net
592 / 489 / 39
Регистрация: 21.07.2012
Сообщений: 1,668
19.02.2013, 18:44 5
Fmamedov, Упаковка\распаковка - это миграция из стека в кучу и наоборот.
Например
C#
1
2
3
int i = 1; 
obj o = (obj)i; //насильно пихаем int в object
int j = (int)o;//так же достаем,зная что там лежит именно int
Где то там,получаем такой код
C#
1
2
IL_0004:  box    [mscorlib]System.Int32   //obj o = (obj)i; 
IL_000b:  unbox.any  [mscorlib]System.Int32 //int j = (int)o;
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
19.02.2013, 20:59 6
Цитата Сообщение от Noob.net Посмотреть сообщение
Упаковка\распаковка - это миграция из стека в кучу и наоборот.
Не обязательно.

Вообще стек/куча - это детали реализации, не стоит на них зацикливаться.
Единственное, что нужно знать - это то, что при боксинге происходит копирование. Вот основное знание.
0
136 / 138 / 18
Регистрация: 26.07.2010
Сообщений: 911
19.02.2013, 21:07 7
Цитата Сообщение от kolorotur Посмотреть сообщение
Единственное, что нужно знать - это то, что при боксинге происходит копирование. Вот основное знание.
Ну, как мы с вами выяснили недавно, то копирование происходит всегда, я думаю гораздо важнее, так это то, что после боксинга объект так просто не удалится => останется в памяти.
Т.е. расход ресурсов а при упаковке еще и производительности.
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
19.02.2013, 21:19 8
Цитата Сообщение от n1l Посмотреть сообщение
копирование происходит всегда
При передаче/присваивании - да.
А при боксинге еще и при вызове методов и именно этот момент является основным для понимания.

Цитата Сообщение от n1l Посмотреть сообщение
гораздо важнее, так это то, что после боксинга объект так просто не удалится => останется в памяти.
В неуправляемой среде - да, это было бы действительно важно.
В случае же с CLR, где памятью заведует довольно эффективный сборщик, подобные моменты уходят на второй план.
Собственно, именно для этого сборщик и сделали.

Цитата Сообщение от n1l Посмотреть сообщение
Т.е. расход ресурсов а при упаковке еще и производительности.
Расход там настолько незначительный, что даже не стоит о нем запариваться.
По крайней мере, я пока еще не встречал ситуации, в которой боксинг оказывал бы сколь-нибудь значительное влияние на расход ресурсов (не встречал - не значит, конечно же, что таких ситуаций нет).
Если же структура у вас размером больше 16-и байт, то стоит серьезно задуматься о том, чтобы сделать ее классом.
0
Темная сторона .Net
592 / 489 / 39
Регистрация: 21.07.2012
Сообщений: 1,668
19.02.2013, 21:23 9
Цитата Сообщение от kolorotur Посмотреть сообщение
Вообще стек/куча - это детали реализации,
это подтверждается тем,что в куче могут быть свои стеки,правильно?
Где-то генерал Липперт писал такое)
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
19.02.2013, 21:53 10
Цитата Сообщение от Noob.net Посмотреть сообщение
это подтверждается тем,что в куче могут быть свои стеки,правильно?
Не совсем.
Деталь реализации (Implementation detail) - это функционал, не являющийся обязательством со стороны разработчика платформы (майкрософта) перед конечными пользователями (разработчиками ПО): он может эту деталь изменять по своему усмотрению от версии к версии, не уведомляя разработчиков и не предоставляя документацию по этим моментам. То есть это - не контракт и не стоит приложение строить таким образом, чтобы оно зависело от этих деталей.

Ну это примерно как обнаружить в платформе баг, эксплуатация которого дает вам как пользователю какие-то бонусы или обходные пути, и строить логику своего приложения вокруг эксплуатации этого бага. Баг в следующей версии платформы пофиксят и ваше приложение станет бесполезным.

Если вы, например, возьмете официальную документацию - спецификацию языка С#, то не увидите в довольно точном документе слов о том, что-де структуры выделяются в стеке тогда-то, а в куче - тогда-то. Только весьма обтекаемые фразы в стиле "структуры, будучи значимыми типами, не требуют выделения памяти в куче" или "обычно память под структуру выделяется в стеке". Другими словами, спецификация языка не обязывает того, кто будет писать реализацию этого языка (компилятор, например, или порт фреймворка под линупс/макось) выделять память под структуры строго в определенном месте.

Другое дело оператор stackalloc для выделения памяти именно в стеке - там все строго, ибо это - контракт, то есть обязательство перед разработчиками ПО, что данный оператор имеет конкретный функционал. Значит вокруг этого оператора можно строить логику приложения - его поведение будет кочевать из версии к версии или по крайней мере информация о любых изменниях, касающихся его работы, будет предоставлена заранее.

Как-то так.
1
Темная сторона .Net
592 / 489 / 39
Регистрация: 21.07.2012
Сообщений: 1,668
19.02.2013, 22:05 11
Цитата Сообщение от kolorotur Посмотреть сообщение
довольно точном документе слов о том, что-де структуры выделяются в стеке тогда-то, а в куче - тогда-то.
Как будто переводили =)
If the relevant thing was their allocation details then we’d have called them “heap types” and “stack types”. But that’s not relevant most of the time. Most of the time the relevant thing is their copying and identity semantics.
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
19.02.2013, 23:05 12
Цитата Сообщение от Noob.net Посмотреть сообщение
If the relevant thing was their allocation details then we’d have called them “heap types” and “stack types”. But that’s not relevant most of the time. Most of the time the relevant thing is their copying and identity semantics.
Ну, собственно, о чем я выше и писал.
0
136 / 138 / 18
Регистрация: 26.07.2010
Сообщений: 911
20.02.2013, 16:15 13
Цитата Сообщение от kolorotur Посмотреть сообщение
При передаче/присваивании - да.
А при боксинге еще и при вызове методов и именно этот момент является основным для понимания.
Я не понял этого предложения

Цитата Сообщение от kolorotur Посмотреть сообщение
В неуправляемой среде - да, это было бы действительно важно.
В случае же с CLR, где памятью заведует довольно эффективный сборщик, подобные моменты уходят на второй план.
Собственно, именно для этого сборщик и сделали.
Ну, это если вы все ссылки уберете.

Цитата Сообщение от kolorotur Посмотреть сообщение
Расход там настолько незначительный, что даже не стоит о нем запариваться.
По крайней мере, я пока еще не встречал ситуации, в которой боксинг оказывал бы сколь-нибудь значительное влияние на расход ресурсов (не встречал - не значит, конечно же, что таких ситуаций нет).
Если же структура у вас размером больше 16-и байт, то стоит серьезно задуматься о том, чтобы сделать ее классом.
Потому что был скорее всего представлен как единичная операция.
0
1 / 1 / 0
Регистрация: 12.01.2010
Сообщений: 18
18.07.2013, 00:29 14
Цитата Сообщение от Fmamedov Посмотреть сообщение
И последнее. В приведенном выше коде будет производится операция упаковки, или она производится только в том случае, когда требуется приведение к типу object?
И все таки будет. CLR via C#, second edition, Jefrey Richter, page 123
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
18.07.2013, 02:17 15
Цитата Сообщение от vikont Посмотреть сообщение
И все таки будет.
В приведенном автором коде? С чего это вдруг?

Цитата Сообщение от vikont Посмотреть сообщение
CLR via C#, second edition, Jefrey Richter, page 123
Там показана визуализация расположения в памяти локальных переменных и их значений.
А вопрос был про массивы.
Вот этот код:
C#
1
int[] array = new array[10];
Не будет вызывать никаких распаковок/запаковок.
1
1 / 1 / 0
Регистрация: 12.01.2010
Сообщений: 18
18.07.2013, 09:26 16
Вы правы, упаковок не происходит. Разобрался наконец.
0
101 / 101 / 15
Регистрация: 23.05.2012
Сообщений: 260
18.07.2013, 13:49 17
Вот и меня заинтересовали.

А какая блин разница? Пол форума про упаковки распаковки стеки кучи значения ссылки....

Мы что на разделе ассемблера???

Или есть какой-то подводный айсберг с которым я не сталкивался? и который может существенно испортить жизнь?

Мне пока удавалось не заморачиваться на это и обойтись такой логикой:

Си это же Си!! ??

С++:
есть 2 варианта объявления переменной (да и объекта)

C#
1
2
3
4
5
6
7
8
int a; // это если хотите в стеке мне хватало в сегменте данных памяти приложения те самые 4 байта и т.д.
        // при этом а - это значение в этих 4 байтах
 
int *ptrA// это указатель на область памяти где эти 4 байта выделены, т.е. ptrA - адрес
 
суть 
 
ptrA = &a// ГДЕ & - взять адрес переменной
Добавлено через 13 минут
А далее динамическое выделение памяти, то есть то которое хрен знает сколько было возможно с помощью
C#
1
new
И тут началась жизнь:

C#
1
2
3
4
5
class A
{
     int i;
     int j;
}
Если A a, то
C#
1
2
a.i=...
a.j=...
Если А *ptrA, то

C++
1
2
a->i=...
a->j=...
И код на С++ погряз в префиксах

С# решили долой -> * & ^

все будет
C#
1
a.i=
только "основные типы" суть значение (.)
"классы" суть ссылки (->)

Следствие

int a,b;
a=b//копируется значение

"class" A,B
A=B//копируется ссылка т.е. "ptrA=ptrB" т.е. адреc

Вот и вопрос что я такого упустил и нафиг себе мозг засорять ненужной информацией
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
18.07.2013, 17:41 18
Цитата Сообщение от DPW Посмотреть сообщение
А какая блин разница? Пол форума про упаковки распаковки стеки кучи значения ссылки....
1. При неосторожном использовании структур можно довольно серьезно просадить производительность именно из-за постоянных распаковок/запаковок.
2. Не зная ситуаций, когда происходит перепаковка и/или не зная последствий перепаковки, можно провести долгие ночи с отладчиком, пытаясь понять, почему вот тут значение вроде как изменяется, а когда использую переменную вот тут — оно старое.
3. Людям просто нравится этот язык и платформа и они интересуются тем, как там внутри все устроено. Вполне нормальное желание для увлекающегося человека, как мне кажется.

Цитата Сообщение от DPW Посмотреть сообщение
С# решили долой -> * & ^
Самое смешное, что в C# всё это есть, кроме последнего (если не считать оператора XOR).
0
101 / 101 / 15
Регистрация: 23.05.2012
Сообщений: 260
18.07.2013, 18:45 19
Цитата Сообщение от kolorotur Посмотреть сообщение
При неосторожном использовании структур...
Вот если забыть что все эти int'ы и doubl'ы структуры (а они та и есть те самые значимые) слово struct последний раз использовал 1000 лет назад. Все что хоть проще самого простого все равно class. Дабы в С# (не замарачиваясь на вот ЭТИ тонкости) выглядят они ну пипец одинаково. Более того один черт ты конструкторик какой никакой да пару методов-свойств... да и припишешь.

Цитата Сообщение от kolorotur Посмотреть сообщение
Не зная ситуаций, когда происходит перепаковка и/или не зная последствий
Вот а я о чем. Терминов по вводили... мама дорогая кучи фигучи управляемая а что если неуправляемая... КАПЕЦ!!!
А суть то вся таже. НЕТ классам в памяти приложения (бишь стеке), ВСЕ И ВСЯ (за исключением...) в динамическую память.
И ввели единый синтаксис для ВСЕГО.
Цитата Сообщение от kolorotur Посмотреть сообщение
Самое смешное, что в C# всё это есть
Бесспорно небезопасный код суть С++, но вопрос если есть С++ на...зачем лесть куда не надо. С++ - это мегаХРЕНЬ. А С# офигенно упрощенно шикарный и, что не мало важно, оставшийся таки сверхфункциональным язык. созданный для прикаладного ПО. Или кто-то там драйвера и операционки на нем пишет?

Я с появлением С# еще присматривался, но после VS2003 (и появления в С++ ^ от .NET до кучи ко всему прежнему) послал этот С++ к бабушке на... холодец. Оно вещь конечно хорошая но все эти префиксы так грузят и грязнят код а С# - красота да и только: прост читабелен элегантен

РЕЗЮМЕ по п.2:
Вот терминов много а суть одна:
"экземпляр класса" хранит адрес и его если что и копирует (последствия... да изменяется все везде т.к. объект та один)
"экземпляр структуры" суть значение его (значение) и копирует (последствия... новая переменная новый объект в памяти со своим значением (пусть какое-то время и совпадающим))

А при передаче в методы... ну так там всегда копия создавалась пока пальцем (* или ref) не ткнешь что его-его родного...

Цитата Сообщение от kolorotur Посмотреть сообщение
Вполне нормальное желание для увлекающегося человека
ну а вот здесь та как с тобой не согласиться. Интересующийся... ДА. CLR дабы покорчить из себя DirectX (не судите за аналогию прослойку между железом наплодившимся и ПипецМегаСообществом программистов, интересующихся, студентов-школяров, отнефигделающих, и вообще 2 пыца и фотоальботмчик гуманитариев которым и язык та знать не надо а мал-мал да таки по прикольней PowerPointa что-нибудь да замутят) вообще много чего породил и "кучи" и "некучи". А суть та таже осталась "динамическая" и "и хрен там было размер массива по ходу поменять 10 значит 10 или const int n=10".

Но вот "молодежь" понаслышав ЭТО ВСЕ лезет туда где норовит офигеть взорвать себе мозг а потом не по делу кучами интересоваться и при ошибках в структуре программы упаковки городить. Хотя я думаю ты согласишься что проблемы такого рода естественно бывают но ох редко дюже.

Сомневаюсь что кто-то в программа будет путем
C#
1
2
3
int a=5;
int b=a;
b=3;
пытаться а изменить.

Все что надо знать
В метод - копия (если прямо иного не сказано)
Из List'а достал - он же.

Накидывайтесь
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
18.07.2013, 19:49 20
DPW, один из самых частоиспользуемых компонентов CLR - итераторы (которые создаются каждый раз при вызове foreach, linq-запроса и пр) - являются мутабельными структурами. Оп-па, видимо авторы .Net не знали, что
Цитата Сообщение от DPW Посмотреть сообщение
слово struct последний раз использовали 1000 лет назад. Все что хоть проще самого простого все равно class.
0
18.07.2013, 19:49
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
18.07.2013, 19:49
Помогаю со студенческими работами здесь

Предполагается ли в C# синтаксис для создания переменной того типа, который указан в переменной Type type
Как это мне представляется: Type type = new double().GetType(); type a = 3.2; type b = 4.1;...

Cannot access a nonstatic member of outer type 'ClassLibrary1.Form1' via nested type 'ClassLibrary1.Form1.Spr'
ругается на SaveAttribute(&quot;Sinonim&quot;, value) данная ошибка уже давно была, забыл что я делал....

Циклическая ссылка (A circular reference was detected while serializing an object of type 'tblProduct')
Подскажите в чем проблема,спасибо. Есть вспомогательный класс public class ListObjectsFromDB...

The ViewData item that has the key 'TownDepart.TownName' is of type 'System.String' but must be of type 'IEnum
Вот представление &lt;%@ Page Title=&quot;&quot; Language=&quot;C#&quot; MasterPageFile=&quot;~/Views/Shared/Air.Master&quot;...

Warning: The type 'lala' conflicts with the imported type...
Создал итем в проекте BuilderChartHelper.cs В нем добавил два класса. Причем в конструкторе одного...

Реализовать метод string[] Method(Type type), который будет выводить все члены, видимые вне сборки, помеченные атрибута
Пожалуйста, помогите. Реализовать метод string Method(Type type), который будет выводить все...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru