Аннотация:
В статье обсуждается вопрос о том, почему большинство языков программирования для платформы .NET не позволяют объявлять конструкторы по умолчанию для структур (т.е. для значимых типов).
Здравствуйте, Тепляков Сергей Владимирович, Вы писали:
ТСВ>В статье обсуждается вопрос о том, почему большинство языков программирования для платформы .NET не позволяют объявлять конструкторы по умолчанию для структур (т.е. для значимых типов).
Вот на этот вопрос я все же ответа не получил. Обнуление — замечательно, а если, допустим, я хочу конструктор по умолчанию, который присваивает полям ненулевое значение — почему нельзя штатными средствами, без Emit и т.д. ? Для классов — можно, присваивайте что угодно в этом конструкторе, для структур почему-то только обнуление.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Вот на этот вопрос я все же ответа не получил. Обнуление — замечательно, а если, допустим, я хочу конструктор по умолчанию, который присваивает полям ненулевое значение — почему нельзя штатными средствами, без Emit и т.д. ? Для классов — можно, присваивайте что угодно в этом конструкторе, для структур почему-то только обнуление.
Одной из главных причин отсутствия пользовательских конструкторов по умолчанию для структур заключается в падении производительности при работе с массивами.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK>Одной из главных причин отсутствия пользовательских конструкторов по умолчанию для структур заключается в падении производительности при работе с массивами.
Гм. Как-то не очень убедительно.
Во-первых, при инициализации нулями никто не мешает оставить существующий вариант
Во-вторых, все равно им как-то придется потом присваивать значение, если нужен не 0, и получится то же самое, только код будет менее наглядным. А нули можно предварительно загнать по всем байтам, как это сейчас и делается.
(Кстати, такой вопрос. ТС утверждает, что инициализация нулем идет одной командой newobject, которая обнуляет. Что значит "обнуляет" ? А если там float или double, да не одно такое поле? Для них же вовсе не нулевые байты нужны. Команда эта настолько интеллектуальна, что сможет разобраться ?)
В-третьих, для всех элементов массива инициализация одна и та же, так что достаточно сформировать один элемент, а потом его размножить копированием памяти
И в четвертых, если даже некоторая конструкция в определенных ситуациях может дать неэффктивное решение, разве это основание ее запрещать ?
Здравствуйте, Тепляков Сергей Владимирович, Вы писали:
ТСВ>Однако при создании экземпляра типа CustomValueType с помощью Activator.CreateInstance наш конструктор по умолчанию будет вызван, а при вызове метода CreateWithNew и создания экземпляра значимого типа с помощью new T() – нет.
Самое интересное и не обьяснили. Почему new T() не вызывает конструктор?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Гм. Как-то не очень убедительно.
Ответа не получил и тебе оно не понравился — это разные вещи.
PD>Во-вторых, все равно им как-то придется потом присваивать значение, если нужен не 0,
Это будет сделано явно, а не за сценой.
PD> и получится то же самое, только код будет менее наглядным.
Более наглядным.
PD>(Кстати, такой вопрос. ТС утверждает, что инициализация нулем идет одной командой newobject, которая обнуляет. Что значит "обнуляет" ?
То и значит — заполняет выделенную память нулями.
PD> А если там float или double, да не одно такое поле?
Все равно нулями.
PD> Для них же вовсе не нулевые байты нужны.
Это еще почему? К примеру, для сингла согласно IEEE 754:
Нет гарантии при условии наличия пользовательского дефолтного конструктора, что результат будет идентичным.
PD>И в четвертых, если даже некоторая конструкция в определенных ситуациях может дать неэффктивное решение, разве это основание ее запрещать ?
Это основание сделать ее применение явным.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, Sinatr, Вы писали:
S>Самое интересное и не обьяснили. Почему new T() не вызывает конструктор?
Все таки интересно вы статью читаете:
Одной из главных причин отсутствия пользовательских конструкторов по умолчанию для структур заключается в падении производительности при работе с массивами.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
PD>>Гм. Как-то не очень убедительно.
AVK>Ответа не получил и тебе оно не понравился — это разные вещи.
Ты, как всегда, в своем репертуаре — переходишь на мое личное отношение.
PD>>Во-вторых, все равно им как-то придется потом присваивать значение, если нужен не 0,
AVK>Это будет сделано явно, а не за сценой.
Да, только вот почему-то для классов это можно сделать явно через конструктор, а для value — нельзя. Почему в одном случае эта "явность" через конструктор не оказывается "за сценой", а в другом оказывается — так и остается неясным.
PD>> и получится то же самое, только код будет менее наглядным.
AVK>Более наглядным.
Хм. Как-то я считал, что обычно использование конструктора является более наглядным, чем присваивание после него нескольким полям. Как минимум хотя бы потому, что это присваивание придется делать везде, где эта постинициализация нужна. Можно, конечно, метод init еще написать и его везде вызывать, но это тоже наглядности не прибавит, не говоря уж о том, что можно в каком-то месте его и забыть вызвать...
AVK>Это еще почему? К примеру, для сингла согласно IEEE 754:
Да, тут я неправ.
PD>>В-третьих, для всех элементов массива инициализация одна и та же, так что достаточно сформировать один элемент, а потом его размножить копированием памяти
AVK>Нет гарантии при условии наличия пользовательского дефолтного конструктора, что результат будет идентичным.
А это уж компилятора дело определить, есть гарантия или ее нет. Если и впрямь есть побочный и т.п. эффект — то нельзя, а иначе можно. Не знаю, умеет ли это C# компилятор, а С++ комаплятор вполне умеет, он и не такое умеет.
PD>>И в четвертых, если даже некоторая конструкция в определенных ситуациях может дать неэффктивное решение, разве это основание ее запрещать ?
AVK>Это основание сделать ее применение явным.
Здравствуйте, Pavel Dvorkin, Вы писали:
AVK>>Ответа не получил и тебе оно не понравился — это разные вещи. PD>Ты, как всегда, в своем репертуаре — переходишь на мое личное отношение.
При чем тут твое личное отношение? Ты заявил что ответа там нет. А он есть.
PD>>>Во-вторых, все равно им как-то придется потом присваивать значение, если нужен не 0, AVK>>Это будет сделано явно, а не за сценой. PD>Да, только вот почему-то для классов это можно сделать явно через конструктор, PD> а для value — нельзя.
Почему нельзя? Можно. Нельзя дефолтный конструктор, вызываемый автоматически. А обычные конструкторы у структур можно.
PD> Почему в одном случае эта "явность" через конструктор не оказывается "за сценой", а в другом оказывается — так и остается неясным.
Потому что массивы. Массив классов это просто массив нулей.
AVK>>Нет гарантии при условии наличия пользовательского дефолтного конструктора, что результат будет идентичным. PD>А это уж компилятора дело определить, есть гарантия или ее нет.
А если нет ее? Будет разное поведение? Или ошибка компиляции.
PD> Если и впрямь есть побочный и т.п. эффект — то нельзя, а иначе можно. Не знаю, умеет ли это C# компилятор
Компилятор C# вообще негодное для этого место. Это может делать только JIT.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Sinatr, Вы писали:
S>>Самое интересное и не обьяснили. Почему new T() не вызывает конструктор?
AVK>Все таки интересно вы статью читаете: AVK>
AVK>Одной из главных причин отсутствия пользовательских конструкторов по умолчанию для структур заключается в падении производительности при работе с массивами.
Вот про это падение производительности при работе с массивами как-то мутно написано.
Ясное дело, что занулить блок памяти — это просто и быстро. Но когда 0 по-умолчанию не устраивают, то все равно потом придется пробежаться по массиву и инициализировать нужные поля вручную. То есть по сути выполнив N раз тот самый конструктор по-умолчанию, который компилятор не удосуживается выполнить сам. Где тут профит в производительности?
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, AndrewVK, Вы писали:
AVK>При чем тут твое личное отношение? Ты заявил что ответа там нет. А он есть.
Есть такое хорошее слово ИМХО. По твоему мнению (твое ИМХО) он там есть. По моему мнению (мое ИМХО) — несколько сомнительно. Заметь, я не утверждаю, что его нет, я лишь говорю — сомнительно. Ты же категорично утверждаешь — есть, и все.
PD>>>>Во-вторых, все равно им как-то придется потом присваивать значение, если нужен не 0, AVK>>>Это будет сделано явно, а не за сценой. PD>>Да, только вот почему-то для классов это можно сделать явно через конструктор, PD>> а для value — нельзя.
AVK>Почему нельзя? Можно. Нельзя дефолтный конструктор, вызываемый автоматически. А обычные конструкторы у структур можно.
PD>> Почему в одном случае эта "явность" через конструктор не оказывается "за сценой", а в другом оказывается — так и остается неясным.
AVK>Потому что массивы. Массив классов это просто массив нулей.
Замечательный способ дискутирования. Берется одна фраза моего ответа, вторая пока что откладывается, при этом, естественно, изменяется смысл, и на этот измененный смысл делается ответ. Вместо общего вопроса, о том почему идейно нельзя (явность) получилось 2 вопроса , на которые и дается 2 банальных ответа.
Далее. Насчет очевидности конструктора против присваивания полям после конструктора ответа не нашлось, поэтому этот кусок просто был убран. Не было его и все тут.
PD>>А это уж компилятора дело определить, есть гарантия или ее нет.
AVK>А если нет ее? Будет разное поведение? Или ошибка компиляции.
А это внутреннее дело компилятора, он и должен определить, есть гарантия или нет. Например, С++ компилятор может придти к выводу (в Release, конечно), что вот эту функцию вызывать вообще незачем, хотя ее вызов явно стоит. Вместе со всем ее графом вызываемых из нее функций. Потому что он проанализировал код и определил, что никакого эффекта от его вызова не будет, а стало быть, и вызывать незачем. Это и есть оптимизирующий компилятор. И никакого разного поведения (кроме скорости, конечно) не будет по сравнению с Debug, где эта функция честно вызывается, молотит свои миллисекунды (или не милли), а в результате никакого влияния на последующие действия нет.
Так что если гарантия есть — построить один код, если нет — другой. Хорошему компилятору это сделать — раз плюнуть. Вот в том примере моем, где выбрасывается целый граф вызовов, стоит вставить printf где-нибудь в какой-нибудь функции этого графа — и он выброшен полностью не будет. То, что нужно для этого printf — будт вычисляться, а то, что не нужно — все равно выбросит.
PD>> Если и впрямь есть побочный и т.п. эффект — то нельзя, а иначе можно. Не знаю, умеет ли это C# компилятор
AVK>Компилятор C# вообще негодное для этого место. Это может делать только JIT.
И это не совсем верно. JIT, верно, может оптмизировать построение машинных команд из псевдокода (байт-кода, IL, ...). А вот преобразования исходного кода и его оптимизация не на уровне команд, а на уровне структуры всей программы — не его дело. По крайней мере той его части, которая отвечает за перевод из IL в машинные команды. Вот если у JIT есть часть, которая занимается глобальной обработкой всей программы (то же выбрасывание ненужных вызовов и прочая оптимизация), то да. Не знаю, есть ли такое у нынешних JIT, но если даже и есть — это лишь значит, что эта функция перенесена с develpoment PC на target PC. Там ее, выполнять в некотором смысле лучше — можно учесть особенности target PC.
Не уверен, правда. что JIT сможет это делать на уровне C++ компилятора. У него просто мало времени на это. У С++ компилятора времени сколько угодно, хоть час, а на время запуска программы все же серьезные ограничения накладываются.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Есть такое хорошее слово ИМХО. По твоему мнению (твое ИМХО) он там есть.
Он там есть безо всякого имхо.
AVK>>Потому что массивы. Массив классов это просто массив нулей. PD>Замечательный способ дискутирования. Берется одна фраза моего ответа, вторая пока что откладывается, при этом, естественно, изменяется смысл, и на этот измененный смысл делается ответ. PD> Вместо общего вопроса, о том почему идейно нельзя (явность) получилось 2 вопроса , на которые и дается 2 банальных ответа.
Я не понял в чем твои претензии и где вдруг смысл поменялся.
PD>>>А это уж компилятора дело определить, есть гарантия или ее нет. AVK>>А если нет ее? Будет разное поведение? Или ошибка компиляции. PD>А это внутреннее дело компилятора
Ну то есть первое? И случайно поправив код так, чтобы компилятор не угадал с чистотой можно очень сильно поменять поведение?
PD>Например, С++ компилятор может придти к выводу (в Release, конечно), что вот эту функцию вызывать вообще незачем, хотя ее вызов явно стоит.
Это совсем другое — тут поведение программы в рантайме не меняется.
PD>Так что если гарантия есть — построить один код, если нет — другой.
Вот только это не отменяет исходной проблемы — все равно остается ситуация, когда просто создание массива структур приведет к огромной просадке производительности. Причем с твоим предложением эта просадка еще и становится менее предсказуемой.
AVK>>Компилятор C# вообще негодное для этого место. Это может делать только JIT. PD>И это не совсем верно.
Это совсем верно. Вызов конструктора по умолчанию для структур выполняет JIT.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, VTT, Вы писали:
VTT>Ясное дело, что занулить блок памяти — это просто и быстро. Но когда 0 по-умолчанию не устраивают, то все равно потом придется пробежаться по массиву и инициализировать нужные поля вручную. То есть по сути выполнив N раз тот самый конструктор по-умолчанию, который компилятор не удосуживается выполнить сам.
Верно. Но, к счастью, для современных процессоров это очень скромный оверхед.
VTT> Где тут профит в производительности?
Профит тут в том, что конструкция new MyStruct[100500] не приведет неявно к большому объему исполнения кода.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, VTT, Вы писали:
VTT>Ясное дело, что занулить блок памяти — это просто и быстро. Но когда 0 по-умолчанию не устраивают, то все равно потом придется пробежаться по массиву и инициализировать нужные поля вручную. То есть по сути выполнив N раз тот самый конструктор по-умолчанию, который компилятор не удосуживается выполнить сам. Где тут профит в производительности?
Например для List а задается избыточные данные мссива, которые не нужно инициализировать. И обычно данные присваиваются (копирутся), а не модифицируются.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>Он там есть безо всякого имхо.
PD>>И это не совсем верно. AVK>Это совсем верно. Вызов конструктора по умолчанию для структур выполняет JIT.
Я и забыл, что имею дело с человеком, который знает истину в последней инстанции. Все, умолкаю.
Здравствуйте, AndrewVK, Вы писали:
S>>Самое интересное и не обьяснили. Почему new T() не вызывает конструктор? AVK>Все таки интересно вы статью читаете: AVK>
AVK>Одной из главных причин отсутствия пользовательских конструкторов по умолчанию для структур заключается в падении производительности при работе с массивами.
И как это связано с вопросом? Разверну вопрос: почему генерик new T() не вызывает конструктор, а new SomeValueType() — вызывает?
Здравствуйте, Sinatr, Вы писали:
S>>>Самое интересное и не обьяснили. Почему new T() не вызывает конструктор? AVK>>Одной из главных причин отсутствия пользовательских конструкторов по умолчанию для структур заключается в падении производительности при работе с массивами. S>И как это связано с вопросом?
Это ответ на него.
S> Разверну вопрос: почему генерик new T() не вызывает конструктор, а new SomeValueType() — вызывает?
Потому что дефолтный конструктор "вызывается" при конструировании массива для каждого его элемента. Логически, разумеется, а не реально. А вот кастомный конструктор нужно вызывать реально, поэтому его наличие может привести к внезапному большому объему вычислений на ровном месте.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Тепляков Сергей Владимирович, Вы писали:
ТСВ>>В статье обсуждается вопрос о том, почему большинство языков программирования для платформы .NET не позволяют объявлять конструкторы по умолчанию для структур (т.е. для значимых типов).
PD>Вот на этот вопрос я все же ответа не получил. Обнуление — замечательно, а если, допустим, я хочу конструктор по умолчанию, который присваивает полям ненулевое значение — почему нельзя штатными средствами, без Emit и т.д. ? Для классов — можно, присваивайте что угодно в этом конструкторе, для структур почему-то только обнуление.
Потому что структуры, чаще всего, используются для передачи двоичных данных.
Взял указатель на первый элемент массива структур — записал данные в поток.
Прочитал данные из потока, сказал, что это массив структур.
На этом построены механизмы маршалинга и работа с памятью в целом.
Допустим, мы добавляем Int32 конструктор по-умолчанию m_value = 1;
Затем в коде пишем:
int variable; // 1
TryGetValue(out variable);
Вместо того чтобы просто выделить 4 байта в стеке, мы ещё и вызовем конструктор по-умолчанию и присвоим переменной 1, хотя это абсолютно не нужно.
Едем дальше:
Мы считываем данные из некоего источника, перезаписывая выделенную память. Но при этом 4096 раз будет дёрнут конструктор по умолчанию. Зачем?
А что делать с приведением типов?
int[] array = new int[4096];
fixed (byte* ptr = &array[0])
{
long value = (long*)ptr; // Должны мы здесь дёрнуть конструктор по умолчанию?
}
Я беру в качестве примера простые типы, потому что они ничем не отличаются от кастомных структур при правильном применении. Если же типу нужен конструктор по-умолчанию — сделай его классом. Зачем структурой? А если нужно проинициализировать — сделай статичный метод у этой структуры, который будет заполнять поля и свойства теми данными, которые тебе нужны и вызывай его вместо дефолтного конструктора. Конструктор скрой аттрибутом.
К слову, единственное что напрягает в текущей ситуации это по-умолчанию видимый конструктор по-умолчанию.
int value = new int();
В определённых ситуациях, он может приводить к ошибкам. Например, при использовании new Guid() вместо Guid.NewGuid()
Но я совершенно точно не хотел бы, что вызов new Guid() генерировал случайные величины. Лучше бы его просто не было.
Здравствуйте, LWhisper, Вы писали:
LW>Я беру в качестве примера простые типы, потому что они ничем не отличаются от кастомных структур при правильном применении. Если же типу нужен конструктор по-умолчанию — сделай его классом. Зачем структурой?
Размещение в стеке, а не в куче.
В общем, с тем, что ты написал, я могу согласиться, но только пока речь идет о простых данных (кстати, заметь, в С++ у них нет конструктора вообще, ни с параметрами, ни дефолтного, а вот инициализация ненулем есть, как простых переменных, так и массивов, правда, для массива лишь списком, а не циклом). А вот когда речь идет о структурах, а хочется иметь их в стеке — машинный код должен , во-первых, выделить место в стеке (это элементарно), а потом инициализировать структуру. И вот тут инициализация нулем действительно очень проста. Если же инициализировать нужно не нулем, то все равно происходит инициализация нулем, а потом устанавливаем ненулевые поля. Лишние действия.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Если же инициализировать нужно не нулем, то все равно происходит инициализация нулем, а потом устанавливаем ненулевые поля. Лишние действия.
С точки зрения безопасности — не лишние. Старые данные все равно нало почистить до передачи управления прикладному коду, иначе этот прикладной код может их прочесть.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>С точки зрения безопасности — не лишние. Старые данные все равно нало почистить до передачи управления прикладному коду, иначе этот прикладной код может их прочесть.
Какая такая передача управления прикладному коду происходит в момент, когда выполняется int[] a = new int[10] ?
Ты путаешь обнуление страниц памяти перед передачей их другому процессу (это делает Windows) и обнуление полей структуры, размещенной в своем собственном стеке по правилам C# (или .net) . Даже если стек при этом растет и ему передаются новые страницы, Windows из обнулит сама. А структуру обнуляют совсем по другим причинам. Стек же, кто его знает, что там раньше было.
Впрочем, в С++ не обнуляют, этим должен заняться код программиста, если он не хочет там мусор иметь. Вполне возможно, что и он и не будет обнулять, если, скажем, потом a[i] = b[i] +c[i] — зачем a[i] обнулять-то ?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Какая такая передача управления прикладному коду происходит в момент, когда выполняется int[] a = new int[10] ?
Сейчас — никакой. А вот есть там кастомный дефолтный конструктор будет, то все не так однозначно.
PD>Ты путаешь обнуление страниц памяти перед передачей их другому процессу (это делает Windows) и обнуление полей структуры, размещенной в своем собственном стеке по правилам C# (или .net).
Я ничего не путаю. В CLR разные сборки могут иметь разные права доступа. В пределах одного процесса и даже домена.
PD>Впрочем, в С++ не обнуляют, этим должен заняться код программиста, если он не хочет там мусор иметь.
И в результате имеем непрерывный поток уязвимостей.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Какая такая передача управления прикладному коду происходит в момент, когда выполняется int[] a = new int[10] ?
AVK>Сейчас — никакой. А вот есть там кастомный дефолтный конструктор будет, то все не так однозначно.
А все же можно поподробнее, какая именно передача управления прикладному коду происходит в момент вызова конструктора ? Какой код до этого выполнялся — системный, что ли ? Вроде как нет, так как до этого стояло x = y, например. И почему при вызове кастомного конструктора с параметрами все по-прежнему однозначно, и никаких проблем нет, а вот если без параметров — неоднозначно ?
PD>>Ты путаешь обнуление страниц памяти перед передачей их другому процессу (это делает Windows) и обнуление полей структуры, размещенной в своем собственном стеке по правилам C# (или .net).
AVK>Я ничего не путаю. В CLR разные сборки могут иметь разные права доступа. В пределах одного процесса и даже домена.
А, вот ты о чем. Тут да,согласен, в дотнете надо обнулять еще и по этой причине. Разграничили доступ по стеку — контролируйте его теперь.
PD>>Впрочем, в С++ не обнуляют, этим должен заняться код программиста, если он не хочет там мусор иметь.
AVK>И в результате имеем непрерывный поток уязвимостей.
На которых работает Windows, Linux, да и сам дотнет, как впрочем, и сотни других программ.
Здравствуйте, Pavel Dvorkin, Вы писали:
AVK>>Сейчас — никакой. А вот есть там кастомный дефолтный конструктор будет, то все не так однозначно. PD>А все же можно поподробнее, какая именно передача управления прикладному коду происходит в момент вызова конструктора ?
Конструктор ведь может прочесть собственные поля, верно? И что за данные там будут, если их предварительно не потереть?
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
PD>>А все же можно поподробнее, какая именно передача управления прикладному коду происходит в момент вызова конструктора ?
AVK>Конструктор ведь может прочесть собственные поля, верно? И что за данные там будут, если их предварительно не потереть?
Потереть — я уже согласился. Я спрашиваю о том, что за передача управления прикладному коду происходит ? Из какого кода она происходит ?
Ну а что касается конструктора по умолчанию, то
//////////////////
Некоторые языки, как например, «голый» IL или Managed C++, поддерживают полноценные пользовательские конструкторы по умолчанию для значимых типов, которые позволяют инициализировать состояние структуры произвольным образом, а не только значениями по умолчанию.
////////////////// https://habrahabr.ru/post/152118/
Так что дело тут не в глубокой философии, в дотнете это ничему не противоречит. Причина где-то в C#.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Так что дело тут не в глубокой философии, в дотнете это ничему не противоречит. Причина где-то в C#.
Одной из главных причин отсутствия пользовательских конструкторов по умолчанию для структур заключается в падении производительности при работе с массивами.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
PD>>Так что дело тут не в глубокой философии, в дотнете это ничему не противоречит. Причина где-то в C#.
AVK>
AVK>Одной из главных причин отсутствия пользовательских конструкторов по умолчанию для структур заключается в падении производительности при работе с массивами.
Это я помню. Правда, так и остается неясным, почему в MC++ и IL этого падения нет. Уж в MC++ об этом должны были в первую очередь позаботиться — если в нем было что-то полезное на момент его создания, то это эффективность кода по сравнению с тогдашним С#. Впрочем, может, и с нынешним.
На вопрос же насчет передачи управления пользовательскому коду, я так понимаю, ответа не будет ?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Это я помню. Правда, так и остается неясным, почему в MC++ и IL этого падения нет.
Оно там тоже есть. Но высокий уровень совместимости с С++ важнее.
PD>На вопрос же насчет передачи управления пользовательскому коду, я так понимаю, ответа не будет ?
Ответ уже был.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
PD>>На вопрос же насчет передачи управления пользовательскому коду, я так понимаю, ответа не будет ?
AVK>Ответ уже был.
Вот это ? Это не ответ.
AV>Сейчас — никакой. А вот есть там кастомный дефолтный конструктор будет, то все не так однозначно.
Впрочем, что я... Я и забыл, что имею дело с человеком, который никогда не признает своих ошибок. Все, умолкаю.
Здравствуйте, Pavel Dvorkin, Вы писали:
AVK>>Ответ уже был. PD>Вот это ? Это не ответ. AV>>Сейчас — никакой. А вот есть там кастомный дефолтный конструктор будет, то все не так однозначно.
Нет, не это. А вот это:
Конструктор ведь может прочесть собственные поля, верно? И что за данные там будут, если их предварительно не потереть?
PD>Впрочем, что я... Я и забыл, что имею дело с человеком, который никогда не признает своих ошибок. Все, умолкаю.
Переход на личности, фу.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
PD>Размещение в стеке, а не в куче.
PD>В общем, с тем, что ты написал, я могу согласиться, но только пока речь идет о простых данных (кстати, заметь, в С++ у них нет конструктора вообще, ни с параметрами, ни дефолтного, а вот инициализация ненулем есть, как простых переменных, так и массивов, правда, для массива лишь списком, а не циклом). А вот когда речь идет о структурах, а хочется иметь их в стеке — машинный код должен , во-первых, выделить место в стеке (это элементарно), а потом инициализировать структуру. И вот тут инициализация нулем действительно очень проста. Если же инициализировать нужно не нулем, то все равно происходит инициализация нулем, а потом устанавливаем ненулевые поля. Лишние действия.
Так на этот случай есть unsafe:
MyStruct* block = stackalloc MyStruct[100];
Ничего не вызывает, память 0 не забивает. Самый быстрый способ выделить память в стеке. Инициализируй на здоровье любыми данными, только уж сам обезопасть себя от выстрела в ногу в виде мусора в не инициализированных полях. Как-то я этим даже пользовался. Примерно в то же время мне не хватало конструкторов у структур. Проблема решилась, больше необходимости не возникало. Так что инструмент есть, а вокруг можно хоть аспекты городить, если это действительно нужно.
Делать безопасный кастомизируемый дефолтный коснструктор для структур не вижу смысла, так как единственный профит перед классами (быстрое выделение в стеке) моментально потеряется при работе в safe-контексте за счёт многократного копирования (а в случае массивов ещё и проверок выхода за пределы допустимого диапазона). В unsafe — пожалуйста, stackalloc и вперёд. .NET даже сам эту память почистит, после выхода из метода, так что возможности застрелиться существенно меньше чем в том же С++.
Здравствуйте, VTT, Вы писали:
VTT>Ясное дело, что занулить блок памяти — это просто и быстро. Но когда 0 по-умолчанию не устраивают, то все равно потом придется пробежаться по массиву и инициализировать нужные поля вручную. То есть по сути выполнив N раз тот самый конструктор по-умолчанию, который компилятор не удосуживается выполнить сам. Где тут профит в производительности?
В статье написано, что это накладно для разработчиков CLR. Лишние телодвижения.