Управляемый код/архитектура

Dasar

> Кстати, а чем обучение паскалю принципиально отличается от обучения си?
ничем - одна фигня.
зы
самообучение на Java/C# - намного проще, чем на паскале/C.
потому что Java/C# позволяют хотя бы такой код отладить:

int[] items = new int[3];
for (int i = 1; i <=3; ++i)
  items[i] = i;

alexkravchuk

> потому что Java/C# позволяют хотя бы такой код отладить:
Это не от языка зависит, а от среды разработки. Тот же borland C++ 2-3 позволял подобную пошаговую отладку. А если у тебя только консольный компилятор явы, то не понятно, как ты это отлаживать будешь.

Dasar

> Это не от языка зависит, а от среды разработки. Тот же borland C++ 2-3 позволял подобную пошаговую отладку. А если у тебя только консольный компилятор явы, то не понятно, как ты это отлаживать будешь.
никакая среда разработки C/C++ - не объяснит, почему приведенный код, то работает, а то - нет

ppplva

valgrind - объяснит
буквально носом ткнет

Marinavo_0507

в паскале тоже проверка границ есть, если чё

Dasar

Банальная стандартная задача одного из первых занятий на создание однонаправленного списка - все эти проверки обойдет на раз.

Marinavo_0507

что за задача?

Dasar

создание однонаправленного списка
или любой другой ссылочной структуры данных

alexkravchuk

Нет, понимаешь, в чём дело... В программировании всегда много мест для ошибок, и без этого никак нельзя... 2 основных принципа обучения, это, во-первых, "от простого к сложному", а во-вторых "учатся на ошибках". IMHO, главная трудность с первым принципом, если смотреть на C/C++, что минимальная не-консольная программа довольно велика, и зачастую требует знания архитектур ОС (в случае оконной программы под Windows). Получается тупиковая ситуация, когда с одной стороны, не понимаешь многих вещей (оконная функция, оконный класс, сообщения, куча дескрипторов и т.п. в случае Win32 и изучить которые и понять, зачем и как они работают, без минимального опыта программирования сложно, а скорее практически невозможно.
Я другой пример приведу:
int aa = 3;
double res;
res = aa/10 +0.1;
printf("%f \n",res);

Вопрос, что напечатает эта программа. По-моему, это куда более частых источник проблем для начинающих... И это ведь общая проблема для языков со строгой типизацией, как Ява или C/C++. C/C++ выдаст 0.1, и Ява, насколько я понимаю, тоже... В то время как какой-нибудь php выдаст 0.4, так как у него явных типов нет. И при том, что php в этом плане проще, он "интуитивнее", он и менее строг, и это лично меня очень раздражает, так как в C/C++ я понимаю, с каким типом в какой момент работаю, и что у меня происходит, а в php всё ещё зависит от того, что в переменных будет находиться в момент выполнения. Вот и думай после этого, что лучше... Не уверен поэтому, что php лучше для изучения, несмотря на то, что он проще и удобнее.

Marinavo_0507

и как там можно напортачить?
указатель на локальную структуру взять? грамотный отладчик это поймает
вопрос только, что сложнее, объяснить, почему так списки делать нельзя, или зачем нужно заклинание "public static void main"?

Dasar

>В программировании всегда много мест для ошибок, и без этого никак нельзя
согласен.
но проблема в том, что только адекватные ошибки - позволяют учиться на ошибках,
не адекватные ошибки - обычно просто вгоняют в ступор.
ошибка - core dumped - совсем не адекватная (причем даже у профессиональных программистов:
1. такая ошибка довольно часто встречается
2. все что можно ответить на вопрос "а почему программа так вылетела" - это только пожать плечами
3. почти не видел программ, которые бы совсем не вылетали по одной из таких ошибок, особенно в условиях стресса
)
ошибка - null pointer с номером строки и call stack-ом - уже почти совсем адекватная, и почти сразу позволяет выявить причину
ps
но еще лучше - если бы в тексте ошибки сразу бы указывалось, какая переменная ссылается в никуда.

Dasar

> и как там можно напортачить?

q = CreateNode;
FreeNode(q);
q.Next = CreateNode;

редкий отладчик скажет, что здесь есть ошибка.
редкий человек понимает, почему программа то работает, то - нет.

Marinavo_0507

> но еще лучше - если бы в тексте ошибки сразу бы указывалось,
> какая переменная ссылается в никуда.
это нетрудно получить в том числе из core
проблема обычно в другом - непонятно, почему эта переменная туда ссылается; иногда нужно несколько дней, месяцев, лет, чтобы понять; по сравнению с этим потеря времени на запуск отладчика, даже если это делается полностью вручную, пренебрежима мала

Marinavo_0507

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

Dasar

> вопрос только, что сложнее, объяснить, почему так списки делать нельзя, или зачем нужно заклинание "public static void main"?
и в чем проблема с заклинаниями при обучении?
одним заклинанием, одним меньше...
то, что надо + писать при сложение чисел - это ведь тоже заклинание
или то, что корова - пишется, через "о" - еще одно заклинание.
назови хоть один предмет, где нет большого числа заклинаний?
ps
главное, чтобы был простой способ - это заклинание вспомнить: например, готовый пример, или какой-нибудь wizard.

Dasar

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

Marinavo_0507

> то, что надо + писать при сложение чисел - это ведь тоже заклинание
это не заклинание, а обозначение, причём хорошее: одним знаком обозначается не очень простое действие
причём собственно складывать учат раньше или одновременно
"public static main" - именно заклинание, так как не обозначает ничего (что было бы известно ученику а нужно, чтоб добрые духи не разгневались

Dasar

> проблема обычно в другом - непонятно, почему эта переменная туда ссылается
дык, об этом и речь.
ведь проблема то с core dumped как раз в том, что даже если ты в dump-е видишь, что переменная x равна 5, то в этом случае - даже нет никакой гарантии, что именно мы эту 5 в переменную x и положили.
а есть высокая вероятность, что эта 5 образовалась, когда мы где-то в другом месте написали y=5.

Marinavo_0507

> совсем не понимаю - почему даже профессиональное программирование -
> должно быть настолько сложным
конкретно это - совсем не сложно, а очень просто: даже автоматическая тулза найдёт ошибку
реальные проблемы бывают гораздо сложней
должно ли быть так? я не знаю

Dasar

> конкретно это - совсем не сложно, а очень просто: даже автоматическая тулза найдёт ошибку
ошибаешься, в реальном приложении, конечно, не найдет.
тоже появление потоков - приводит уже к тому - что все эти автоматические тулзы начинают сами валиться.
даже появление событийности - уже не по зубам автоматическим тулзам.

Marinavo_0507

> есть высокая вероятность, что эта 5 образовалась,
> когда мы где-то в другом месте написали y=5
алиасинг и связанные с этим проблемы не исчезает даже при переходе к строгой типизации и автоматическому управлению памятью
профессиональному программисту необходимо уметь эти проблемы решать, поэтому лучше, чтобы он столкнулся с этим на учебных примерах, а не на практике
для непрофессионального ознакомления можно придумать специальные учебные языки, требующие меньшего количества ненужных знаний, чем Java

Dasar

> конкретно это - совсем не сложно, а очень просто: даже автоматическая тулза найдёт ошибку
да, кстати - эти твои хваленые тулзы - ищут ошибку во время компиляции, или во время работы?

Marinavo_0507

конкретно такие ошибки ищутся статическими анализаторами даже для С, на реальных проектах

Marinavo_0507

тоже появление потоков - приводит уже к тому - что все эти автоматические тулзы начинают сами валиться.
даже появление событийности - уже не по зубам автоматическим тулзам.
дык и я про что

Dasar

> алиасинг и связанные с этим проблемы не исчезает даже при переходе к строгой типизации и автоматическому управлению памятью
причем здесь алиасинг?
проблемы с алиасингом - это уже следующая ступень, здесь мы хотя бы можем вспомнить, что да - что мы с одним и тем же работали под несколькими именами.
речь же шла о том, что мы никаких алиасов не создавали, в переменную x значение 5 не писали, но в dump-е мы упорно видим значение 5.

Marinavo_0507

> речь же шла о том, что мы никаких алиасов не создавали,
это только в учебном примере так
в реальном проекте ты уже не будешь уверен, что алиасов не было

Dasar

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

Marinavo_0507

> в своих программах - я уверен, что алиасов - нет, точнее - я уверен,
> что даже если они есть, то проблем они не создают
так не бывает
> смотря как писать
аккуратность важна, и чтоб её выработать, нужно сначала на учебных проектах ощутить важность задачи, и понять, какие вообще бывают подходы к её решению
всякие низкоуровневые штуки изучать тоже нужно, чтобы потом понимать, что ограничения той же java неспроста появились, что люди хотели, как лучше, и местами у них даже получилось

Dasar

в реальных приложениях алиасов порядка на 3-4 меньше, чем, например, вот таких микроучастков кода

Item * item;
int res = CreateItem(&item);
//if (IsError(res return error;
item->y = 5;

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

Dasar

> так не бывает
честнее на твоем месте было сказать - "я так не умею"
> аккуратность важна, и чтоб её выработать, нужно сначала на учебных проектах ощутить важность задачи, и понять, какие вообще бывают подходы к её решению
опять же совсем не понимаю - почему при профессиональном программирование - должна быть так важна - аккуратность.
намного важнее наличие гарантий - что даже в случаи неаккуратности - все будет хорошо

Marinavo_0507

> правильнее было сказать - "я так не умею"
и ты не умеешь, если только ты не тот легендарный программист, который никогда не ошибается
> намного важнее наличие гарантий - что даже в случаи неаккуратности -
> все будет хорошо
автоматические средства получения таких гарантий не универсальны, и работают только на довольно узких классов ошибок

alexkravchuk

> и как раз гарантию, что во всех микроучастках кода - корректно обрабатываются ошибки - получить невозможно.
Я потерял нить дискуссии... О чём вообще говорят, то ли о учебном языке, то ли о программировании в целом. В частности, описанный тобою пример может встречаться в любом языке, и C/C++, и в Java, и PHP, и многие другие.
>> так не бывает
> честнее на твоем месте было сказать - "я так не умею"
Не согласен. То, что работает на маленьких проектах, на больших уже не используешь...
>> аккуратность важна, и чтоб её выработать, нужно сначала на учебных проектах ощутить важность задачи,
>> и понять, какие вообще бывают подходы к её решению
> опять же совсем не понимаю - почему при профессиональном программирование - должна быть так важна - аккуратность.
> намного важнее наличие гарантий - что даже в случаи неаккуратности - все будет хорошо
Так не бывает. Проблемы в любом случае будут, рано или поздно они всплывут. Да, их можно перенести на уровень более сложных проектов, но учиться решать эти проблемы нужно на небольших учебных программах, иначе получится, что тогда, когда ты столкнёшься с проблемами, ты просто не будешь их уметь их решать. И понять, почему каким-то способом писать не нужно тоже можно только на своих ошибках. IMHO, впрочем.

Dasar

> ты не умеешь, если только ты не тот легендарный программист, который никогда не ошибается
я как раз не говорил, что я не ошибаюсь.
я говорил, что в моих программах - алиасы не становятся причинами проблем.
> автоматические средства получения таких гарантий не универсальны
согласен
> и работают только на довольно узких классов ошибок
совсем не согласен
автоматические средства получения гарантий - дают главную гарантию - гарантию адекватности: т.е. эти средства говорят, что если придерживаться правильной стратегии, то даже в случае ошибок - код будет вести себя адекватно.
C/С++/паскаль - дает лишь гарантию лишь для случаев:
придерживаться правильной стратегии, никогда не совершать ошибок.

Dasar

> В частности, описанный тобою пример может встречаться в любом языке, и C/C++, и в Java, и PHP, и многие другие.
в C#/Java - я получаю адекватное поведение - а именно exception со строкой: null pointer в такой-то строке при таком-то call stack-е.
в c/c++/паскале - я получу непонятную ситуацию:
когда при одном окружении= все нормально работают
в другом - запарывается на ровном месте полностью оттестированный кусок кода
в третьем - core dumped.
> Да, их можно перенести на уровень более сложных проектов, но учиться решать эти проблемы нужно на небольших учебных программах, иначе получится, что тогда, когда ты столкнёшься с проблемами, ты просто не будешь их уметь их решать.
ты в противогазе каждый день бегаешь?
нет..., а почему?
ведь ты этим уходишь от проблемы, а вдруг завтра будет все плохо? а ты даже в противогазе бегать не умеешь...

Marinavo_0507

> я говорил, что в моих программах - алиасы не становятся причинами проблем.
какими способами ты получаешь уверенность, что A[i] не изменится незаметно для тебя с помощью алиаса A[j] ?
допустим, ты где-то забыл инициализировать j , и использовалось предыдущее значение
> автоматические средства получения гарантий - дают главную гарантию -
> гарантию адекватности: т.е. эти средства говорят, что если придерживаться
> правильной стратегии, то даже в случае ошибок - код будет вести себя
> адекватно.
адекватность для человека и компьютера - разные понятия
автоматическое управление памятью + строгая типизация дают, например, гарантию, что не возникнет непредвиденной модификации из-за висячей ссылки, но не дают такой гарантии при доступе через индекс, а не через указатель
хотя эффект от таких ошибок одинаковый

Dasar

> какими способами ты получаешь уверенность, что A[i] не изменится незаметно для тебя с помощью алиаса A[j] ?
допустим, ты где-то забыл инициализировать j , и использовалось предыдущее значение
инкапсуляция + readonly интерфейс наружу.

Marinavo_0507

> readonly интерфейс наружу
у тебя совсем нет составных сущностей с возможностью модификации?

Dasar

> у тебя совсем нет составных сущностей с возможностью модификации?
есть, но модификация - в первую очередь, обязательно pull-овая, а не push-овая.

Marinavo_0507

модификация - в первую очередь, обязательно pull-овая, а не push-овая
не совсем понимаю суть трюка
но понятно, что следит за этим не компилятор, а ты лично, и никакой гарантии, что ты корректно опишешь каждую микроситуацию, нет

Marinavo_0507

в c/c++/паскале - я получу непонятную ситуацию:
когда при одном окружении= все нормально работают
в другом - запарывается на ровном месте полностью оттестированный кусок кода
в третьем - core dumped.
ты говоришь про недетермизм
полностью избавиться от влияния среды можно только при вычислении чистых функций в математическом смысле
если тебе удастся разбить задачу на такие функции, с гарантией корректности результата - считай, дело почти сделано

Dasar

> но понятно, что следит за этим не компилятор, а ты лично, и никакой гарантии, что ты корректно опишешь каждую микроситуацию, нет
конечно - нет.
у меня есть главное - у меня в каждый момент работы программы есть четкое понимание - какая часть кода (какой модуль) ответственена за данную ошибку/непонятку.
если в массиве(коллекции) A - какая-то грязь - значит виноват тот модуль, который отвечает за заполнение этого массива.
благодаря pull-у - такой ответственный всегда один - поэтому даже в очень большой программе - за пару минут можно выделить тот модуль, который привел к данной проблеме.

alexkravchuk

если в массиве(коллекции) A - какая-то грязь - значит виноват тот модуль, который отвечает за заполнение этого массива.
благодаря pull-у - такой ответственный всегда один - поэтому даже в очень большой программе - за пару минут можно выделить тот модуль, который привел к данной проблеме.
Момент не понятен. Почему не может быть ситуации, когда запись производится в десятке мест, пусть даже через какой-то интерфейс? Причём так, что в момент записи ты не может понять, что записываешь грязь какую-то?

Marinavo_0507

у меня есть главное - у меня в каждый момент работы программы есть четкое понимание - какая часть кода (какой модуль) ответственена за данную ошибку/непонятку.
аналогичная часто используется и для отслеживания освобождений памяти
только - вот беда - ошибки почему-то случаются, несмотря на простоту формулировки
если подумать, понятно даже, когда и почему
твой трюк с pull я не понимаю, но думаю, что и он либо не 100%-применим, либо не 100%-гарантирован

Dasar

> Почему не может быть ситуации, когда запись производится в десятке мест, пусть даже через какой-то интерфейс? Причём так, что в момент записи ты не может понять, что записываешь грязь какую-то?
вот - это и есть плохая архитектура - не надо так делать (не надо из десяти мест менять одну перменную) в серьезных приложениях.

alexkravchuk

> вот - это и есть плохая архитектура - не надо так делать (не надо из десяти мест менять одну перменную) в серьезных приложениях.
Боюсь, что в реальной жизни без этого никак не обойтись. По сути это глобальные переменные, и по возможности от них полезно избавляться, но ведь это не всегда возможно, иногда они просто необходимы.

Dasar

> Боюсь, что в реальной жизни без этого никак не обойтись. По сути это глобальные переменные, и по возможности от них полезно избавляться, но ведь это не всегда возможно, иногда они просто необходимы.
речь идет о том, что надо делать так, чтобы эта сама переменная брала (тащила/pull-ила) данные из десяти места, а не эти десять мест пихали (push-или) одну бедную переменную.
В первом случае - понятно откуда идет грязь, понятно кто ответственен за ошибку, понятно как сделать систему самодиагностики, и самовостановления,
во втором случае - ничего не понятно.

Andbar

и в чем проблема с заклинаниями при обучении?
одним заклинанием, одним меньше...
помню, как читал в книжке по турбо паскалю про работу с модулем граф. уууу, муть какая-то... Какие-то дурацкие левые две строчки дописывать, непонятно зачем... да еще и анализируй коды ошибок - делать мне нечего... на обычной учебной задаче меня однажды наругали за то, что я затратил лишних 15 минут на то, что впервые в жизни попытался написать проверку входных данных, дабы прога не вылетала если случайно букву вместо цифры введёшь. А тут почему-то тот же контроль данных устраивают. Да и если б сказали что-то типа "напишите такую-то строчку - будет вам графический режим", не устроило бы.... И лишь значительно позже, когда стал ботать некоторые вещи (в т.ч. - асм я этот модуль "признал".
Заклинания можно юзать когда нужно какой-то кусок кода быстренько сделать, лишь бы работало, а в учебном процессе это только вредный для общего понимания элемент. Как только начинаешь понимать, что это не элемент синтаксиса, а какая-то частная вещь, которую почему-то все пишут, но не объясняют, почему, становится жутковато.
Впрочем, эти вещи довольно индивидуальны и воспринимаются по разному на разных стадиях обучения...

Dasar

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

bleyman

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

Marinavo_0507

Распиши, что ли, отличия pull от push с примерами, а мы уж найдём, где прокол.
А то скучно.

Dasar

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

bleyman

Ладно, то, что я сказал - это определение хакера (в олдскульном смысле расслабься =)
Но, кстати, без этого всего ни за что не избавиться от "заклинаний".

Dasar

> Распиши, что ли, отличия pull от push с примерами, а мы уж найдём, где прокол
это push

class Class1
{
public int A1
{
set {_A = value;}
}
public int A2
{
set {_A = value;}
}
public int A
{
get {return _A;}
}
int _A;
}

это pull

class Class1
{
public int A1
{
set
{
_A1 = value;
_A1_ChangeTick = DateTime.UtcNow;
}
}
int _A1;
DateTime _A1_ChangeTick;
public int A2
{
set
{
_A2 = value;
_A2_ChangeTick = DateTime.UtcNow;
}
}
int _A2;
DateTime _A2_ChangeTick;
public int A
{
get { if (_A1_ChangeTick > _A2_ChangeTick) return _A1; else return _A2;}
}
}

> мы уж найдём, где прокол
проколов - нет
есть только повышенные требования по памяти и производительности.

alexkravchuk

По всей видимости он имел в виду то, что можно окружить опасные объекты дополнительной интерфейсной оболочкой, например если у нас есть глобальный массив, то создать специальную функцию set_elem(i,val) для присваивания элемента, и всю работу вести через такую функцию, запретив прямое обращение к элементам. Плюс такого подхода в том, что при отладке можно контролировать обращения к этой переменной, в частности, ввести какое-то хитрое поведение этой функции, например, чтобы она ругалась, когда присваивают какое-то значение, про которое мы пытаемся понять, кто именно и где его присваивает.
Хотя IMHO, это решение не универсально.

Marinavo_0507

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

Dasar

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

alexkravchuk

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

Marinavo_0507

ну без полного лога событий хрен что поймёшь
потому что заметишь неладное, когда A вернёт что-то не то, и окажется оно было присвоено через A1 в момент времени t1 как результат вычисления f(B, C а вот чему было равно в тот момент В и C, уже неизвестно, так как они давно поменялись
полный лог - может привести, и как правило, приведёт к качественному изменению требований к памяти
это всё равно как вместо сборщика мусора просто никогда не освобождать память, "решив" таким образом проблему с висячими ссылками
небезопасно хотя бы потому, что перепутаешь однажды после 8 часов работы A1 и A2, и никакой компилятор не предупредит
и даже если регулярно будешь путать, не предупредит ни разу

Dasar

> Не проще ли сделать так, чтобы переменная была общей, но была добавлена ещё одна переменная, которая хранила бы информацию о том, какая функция последняя вызывалась? А ещё лучше, чтобы просто записывалось, из какой строки какого файла вызывали последний раз функцию?
И кто и что с этой информацией будет делать на стороне пользователя?
что нам даст эта информация?

Dasar

> потому что заметишь неладное, когда A вернёт что-то не то, и окажется оно было присвоено через A1 в момент времени t1 как результат вычисления f(B, C а вот чему было равно в тот момент В и C, уже неизвестно, так как они давно поменялись
приведи полный пример.
ты здесь опять зачем-то применил push-логику.
> небезопасно хотя бы потому, что перепутаешь однажды после 8 часов работы A1 и A2, и никакой компилятор не предупредит
и даже если регулярно будешь путать, не предупредит ни разу
как раз такие опечатки - нормально ловят простейшие тесты.

Marinavo_0507

> ты здесь опять зачем-то применил push-логику.
может, я что-то не понимаю
покажи, как ты собрался эти классы использовать
> как раз такие опечатки - нормально ловят простейшие тесты
как они отловят? поведение класса ведь не зависит от того, A1 или A2 мы используем

Dasar

т.е. не понятно, как делать самодиагностику, и самовостановление.

alexkravchuk

> И кто и что с этой информацией будет делать на стороне пользователя?
> что нам даст эта информация?
Ровно то же, что и информация о том, в какой момент по времени было последняя запись в переменную из твоей функции. А точнее, даже больше скажет, так как если мы храним информацию о строке, то автоматически решается проблема с тем, что мы перепутали функцию.
Со стороны пользователя ни твой пример, ни мой никак не скажется, эта информация полезна и доступна лишь для того, кто имеет доступ к коду этих классов.

Dasar

> покажи, как ты собрался эти классы использовать
эти классы - никак. это утрированный пример.
в реальной программе - A1 и A2 - это внешние по отношению к Class1 переменные.
> как они отловят? поведение класса ведь не зависит от того, A1 или A2 мы используем
проверкой двух инвариантов

int value = random;
c.A1 = value;
Assert.AreEqual(c.A, value);


int value = random;
c.A2 = value;
Assert.AreEqual(c.A, value);

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

alexkravchuk

> небезопасно хотя бы потому, что перепутаешь однажды после 8 часов работы A1 и A2, и никакой компилятор не предупредит
и даже если регулярно будешь путать, не предупредит ни разу
как раз такие опечатки - нормально ловят простейшие тесты.
Нет, не поймают... Более того, у меня лично это одна из распространённых ошибок, когда вводится несколько имён переменной, которая имеет одно и тоже значение (с той целью, чтобы в дальнейшем разделить эти переменные, например когда они кодируют имя скрипта, класс обработки чего-либо и т.п. и поэтому на раннем этапе путаница не приводит к ошибкам, которые проявляются (зачастую очень хитро когда переменным присваиваются разные значения.

alexkravchuk

только не понятно, как в рабочем коде использовать такую технологию проверки, потому что используя бессмысленные данные, до участка кода, который нужно протестировать, можно просто не дойти.

Marinavo_0507

> в реальной программе - A1 и A2 - это внешние по отношению к Class1 переменные.
не понял
с.A1 - внешняя по отношению к C?
> проверкой двух инвариантов
они всегда будут выполняться, независимо от использования класса

Dasar

замечу, что оба утверждения - твои, и они друг другу противоречат, ты уж разберись сам с собой - какое из них правильное.
небезопасно хотя бы потому, что перепутаешь однажды после 8 часов работы A1 и A2, и никакой компилятор не предупредит
они всегда будут выполняться, независимо от использования класса

Marinavo_0507

> и они друг другу противоречат
нет
ты заметишь проблему, полезешь смотреть таймстампы, не знач что они неверные, так как ты год назад что-то перепутал, и никто не заметил

Dasar

ок, пример задачи:
есть экранная кнопка
при наведение на эту кнопку мышки и нажатие - кнопка должна вдавливаться
если кнопку отжимают, то кнопка - должна возвращаться в нормальное положение
при нажатии пробела - кнопка также должна вдавливаться
если пробел отжат - то кнопка должна отжиматься.
Какое будет ваше решение данной задачи?

Marinavo_0507

а если сразу всё нажать, что должно произойти?

Dasar

нажаться
ps
замечу, что из данной постановки задачи - неочевидно, что вообще возможно одновременное нажатие и мышкой, и клавой.

Marinavo_0507

а потом что-то одно отпустить?

Dasar

> а потом что-то одно отпустить?
по идее - нажатой.

Marinavo_0507

> замечу, что из данной постановки задачи - неочевидно,
> что вообще возможно одновременное нажатие и мышкой, и клавой
а вот когда все такие вопросы прояснишь, одни чистые функции и останутся
ещё можно нажать пробел заранее
или мышу нажать в другом месте, а потом навести на кнопку, и аналогично увести

Dasar

ты код - напиши, а не увиливай.

alexkravchuk

Вообще, тут скорее от инструментария оболочки зависит. Но если интерпретировать пример как условный, то я бы так сделал (я всё равно не помню сейчас имена сообщений, поэтому они абсолютно условные):

switch(message){
mouse_push: if_on_object(&knopka)
(*knopka).action(MOUSE_PUSH);
break;
mouse_pop: (*knopka).action(MOUSE_POP);
break;
space_push: (*knopka).action(SPACE_PUSH);
break;
space_pop: (*knopka).action(SPACE_POP);
break;
show: // сообщение на прорисовку экрана
(*knopka).show;
break;
}
/////////////////
class knopka{
status_mouse_key;
status_space_key;
public:
knopka {status_mouse_key=0; status_space_key=0;}
action(int type)
{
switch(type)
{
MOUSE_PUSH: status_mouse_key=1;
MOUSE_POP: status_mouse_key=0;
SPACE_PUSH: status_space_key=1;
SPACE_POP: status_space_key=0;
}
}
show
{
if(status_mouse_key || status_space_key)
show_as_pushed;
else
show_as_usual;
}
};
//////////////////

Marinavo_0507

чёта я не заметил, а как это оказалось, что это я должен код писать?

Dasar

что будет - если сообщения show нет?
например, кнопка - это внешний объект, со своим циклом отрисовки и т.д.

Dasar

зачем - как и в моем примере - ты завел две лишние переменные status_mouse_key и status_space_key - вместо необходимой одной переменной?

Dasar

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

alexkravchuk

ничего - show нужно исключительно для того, чтобы прорисовать кнопку на экране. Другой вопрос, что будет если не будет сообщения об отжатии кнопки (а такое можно допустить но чтобы бороться с этим, нужно смотреть, какие инструменты есть.
Очевидный минус данного примера состоит в том, что проверка осуществляется только по приёму сообщений, и опасно упустить их, и мы будет считать, что кнопка нажата, хотя её давно отжали.

alexkravchuk

зачем они были в твоём примере, я так до конца и не понял. Но в данном случае, переменные кодируют СОСТОЯНИЕ клавиши, которое одной переменной описать невозможно (mean однобитной переменной).

Dasar

> ничего - show нужно исключительно для того, чтобы прорисовать кнопку на экране
что значит ничего? кнопку кто и когда отжимать/нажимать будет?

Marinavo_0507

лень писать, так как не вижу, где тут может алиасинг случиться

Dasar

> но чтобы бороться с этим, нужно смотреть, какие инструменты есть.
допустим - все что мы хотим - есть.

Dasar

> лень писать, так как не вижу, где тут может алиасинг случиться
гордыня - однако.
а ведь даже на таком простом примере - легко показывается, что программисты даже в лучшем случае - или закладываются только на 1% вариантов, или начинают городить килобайты кода.

alexkravchuk

нажимает/отпускает кнопку функция action(msg). show - показывает кнопку на экране. Здесь я написал по системе, когда есть у нас оконная функция, и я работаю с обработчиком сообщений (нажатия кнопок, движения мышью, задание на прорисовку - всё одна функция обработки сообщений как в голом WinAPI или X-Windows. Возможно, если использовать специализированные библиотеки, принцип работы будет другой, но так как схема не определена, я взял то, что пришло в голову.

Dasar

еще раз: мне интересно посмотреть, как измениться твой код, если кнопка - это внешний объект (со своим циклом отрисовки). и этим внешним объектом - мы можем управлять через действия - нажмись/отпустись.

alexkravchuk

>> но чтобы бороться с этим, нужно смотреть, какие инструменты есть.
> допустим - все что мы хотим - есть.
Это не ответ на вопрос, может там вообще готовая библиотека для этого есть.
Но вообще - нужно ещё создать дополнительную функцию проверки статусов клавиш, которая будет корректировать состояния нажатия клавиш всякий раз, когда мы выполняем какую-нибудь зависящую от этих состояний функцию (show в данном случае). Естественно, вызов этой функции помещается внутрь класса, просто я не уверен, что WinAPI просто так это позволит (не помню, и давно не писал под WinAPI). Поэтому надо чётче описать, что именно требуется, и как вести себя в разных ситуациях, тогда можно будет придумать какое-нибудь хорошее решение. Да, конечно какой-то не самый маленький код тут есть

alexkravchuk

> еще раз: мне интересно посмотреть, как измениться твой код, если кнопка - это внешний объект (со своим циклом
> отрисовки). и этим внешним объектом - мы можем управлять через действия - нажмись/отпустись.
Принципиально - не изменится. Точно также есть сложное состояние (так как кнопка может быть нажата несколькими способами в то время как видимое состояние - одно.

Dasar

> Это не ответ на вопрос, может там вообще готовая библиотека для этого есть.
давай договоримся так:
я заказчик, и я попросил решить данную задачу
у меня, как у заказчика есть целый вагон и маленькая тележка всякого барахла - которое может быть тебе пригодиться при решение поставленной задачи, но я только лишь заказчик (а не эксперт поэтому сказать заранее - что из этого барахла ты можешь использовать - не могу, но зато если ты меня попросишь поискать, что-нибудь конкретное, то я пойду посмотрю - есть эта штука или нет.
ps
вот, например, с кнопкой беда вышла - кнопка которая сама отрисовывается есть, а которая через цикл сообщений задачи отрисовывается - такой нет.

Dasar

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

Dasar

> Принципиально - не изменится. Точно также есть сложное состояние (так как кнопка может быть нажата несколькими способами в то время как видимое состояние - одно.
а код где?

alexkravchuk

ок, пусть такая функция будет
можем даже ее GetPressedKeys назвать.
Пусть тогда класс будет
knopka{
int status_mouse_key;
int status_space_key;
public:
knopka {status_mouse_key=0; status_space_key=0;}
// Корректировка статусов кнопки в нужный момент времени
correct_status
{
status_mouse_key=0;
status_space_key=0;
if(GetPressedKeys(KEYBOARD_SPACE
status_space_key=1;
if(GetPressedKeys(MOUSE_BUTTON
status_mouse_key=1;
}
int get_visual_status
{
correct_status;
if(status_mouse_key || status_space_key)
return 1;
else
return 0;
}
// Вывод на экран
show
{
st = get_visual_status;
далее - отрисовка кнопки в зависимости от статуса.
}
// вызывается при подозрительных сообщениях, типа движений мыши, нажатий кнопок и другого.
message
{
correct_status;
}
};

Dasar

вот такое усложнение сможешь добавить?:
действия клавы мы считаем более приоритетные, чем мышиные.
т.е. если мы пробел - отжали, то кнопка должна отжаться, даже если мышь была при этом нажата.
если же при отжатом пробеле - мышь еще раз щелкнуть, то кнопка опять должна нажаться.
и еще раз уточню, что мы пишем не саму кнопку, а допустим только внешний модуль логики к такой кнопке: т.е. кнопка сама по себе, мы (модуль логики отслеживающий клаву и мышку) сами по себе, и мы должны внешние события переводить в события кнопки - нажмись/отпустись.

alexkravchuk

вот такое усложнение сможешь добавить?:
действия клавы мы считаем более приоритетные, чем мышиные.
т.е. если мы пробел - отжали, то кнопка должна отжаться, даже если мышь была при этом нажата.
если же при отжатом пробеле - мышь еще раз щелкнуть, то кнопка опять должна нажаться.
Возможные состояния:
клавиша пробела нажата.
клавиша пробела отпущена, равно как и клавиша мыши.
клавиша пробема отпущена, но мышь остаётся нажатой с момента, когда была нажата была нажата одновременно с клавишей пробела
клавиша мыши отпущена после предыдущего состояния
клавиша мыши вновь нажата, когда пробел отпущен.
Далее, функция correct_status модифицируется:
///////////////////////
correct_status
{
// текущие состояния клавиш мыши/пробела
space_now = GetPressedKeys(KEYBOARD_SPACE);
mouse_now = GetPressedKeys(MOUSE_BUTTON);
// если отпущена ранее нажатая клавиша пробела
if(space_now==0 && status_space_key==1)
{
status_space_key=0;
if(mouse_now)
status_mouse_key= 2; // Особое состояние, которое будет держаться до того момента, пока мышь не отпустят
}
if(mouse_now==0)
status_mouse_key = 0;
// если нажата мышь, которая не находится в том самом "особом состоянии"
if(mouse_now==1 && status_mouse_key !=2)
status_mouse_key = 1;
if(space_now==1)
{status_space_key=1; status_mouse_key = mouse_now;}
}
/////////////////
соответсвенно, функция
int get_visual_status
{
correct_status;
if(status_mouse_key==1 || status_space_key==1)
return 1;
else
return 0;
}
//////////
Вот так... Главное расписать возможные состояния.
Я не понимаю только, к чему ты клонишь. Я устал код писать, лучше прямо скажи, а то спать пойду...
PS: ошибка одна исправлена, а вообще лучше структуру перестроить, чтобы она прозрачнее была.

Dasar

во-первых: хочу сказать, что ты правильно решал данную задачу, и поэтому избежал почти всех ловушек.
У тебя как раз есть один центральный метод, который вытягивает текущее состояние - соответственно все работает, даже если включают две клавы или две мышки, отрубают все это дело совсем, уже не важно зажаты или нет были клавиши при старте кнопки и т.д.
В дополнительном варианте - ты вводишь состояния, что сильно усложняет программу. Теперь уже надо доказывать - что состояния образуют полное множество, что все переходы ты предусмотрел и т.д.
или другими словами - поставленная задача получилось закодированная не явно, т.е. чтобы восстановить информацию о том - а когда же кнопка должна быть у нас нажата/отжата - необходимо проводить логический анализ.
проблема состояний в том, что сразу возникает комбинаторный взрыв - необходимо рассматривать задачу размерности NxK, где N - кол-во состояний, а K - кол-во событий.
вторую задачу, как и первую опять же намного проще решать без состояний - просто описывая тот инвариант, который мы хотим получить.
а хотим мы всего лишь следующего:
isButtonPressed = isSpaceKeyPressed || isMouseKeyPressed && spaceKeyUnpressedTick < mouseKeyPressedTick;
соответственно, и первая, и вторая задачка решаются по одной и той же схеме
первый вариант

void UpdateButtonState
{
   bool isButtonPress = GetCalculatedButtonState;
   if (button.IsPressed != isButtonPress)
     if (isButtonPress)
     button.Press;
     else
     button.Unpress;
}
bool GetCalculatedButtonState
{
   return GetPressedKey(SPACE) || GetPressedKey(MOUSE);
}
void OnButtonPress
void OnMousePress
void OnButtonUnpress
void OnMouseUnpress
void OnKeyStateChanged
void OтПятнаНаСолнцеChanged
  UpdateButtonState;

второй вариант:

void UpdateButtonState
{
   CheckPressChanges;
   bool isButtonPress = GetCalculatedButtonState;
   if (button.IsPressed != isButtonPress)
     if (isButtonPress)
     button.Press;
     else
     button.Unpress;
}
bool GetCalculatedButtonState
{
   return GetPressedKey(SPACE) || GetPressedKey(MOUSE) && spaceKeyUnpressedTick < mouseKeyPressedTick;
}
bool? isPrevKeyPress;
bool? isPrevMousePress
DateTime? spaceKeyUnpressedTick;
DateTime? mouseKeyPressedTick;
void CheckPressChanges
{
   if(isPrevKeyPress != GetPressedKey(SPACE
     if (!GetPressedKey(SPACE
     spaceKeyUnpressedTick = DateTime.UtcNow;
   if(isPrevMousePress != GetPressedKey(MOUSE
     if (GetPressedKey(MOUSE
     mouseKeyPressedTick = DateTime.UtcNow;
   isPrevKeyPress = GetPressedKey(SPACE);
   isPrevMousePress = GetPressedKey(MOUSE);
}
void OnButtonPress
void OnMousePress
void OnButtonUnpress
void OnMouseUnpress
void OnKeyStateChanged
void OтПятнаНаСолнцеChanged
  UpdateButtonState;

Dasar

> Я не понимаю только, к чему ты клонишь.
я клоню к тому, что в правильном коде (и мы видим как раз этому подтверждение - прямо в твоем коде) - нет изменения одной и той же переменной из нескольких участков кода, а есть только один центральный метод - который и осуществляет всю деятельность.
Данная задача идентична начальным теоретическим рассуждения об изменении переменной из нескольких мест: здесь мы также имеем одну "глобальную" переменную (состояние кнопки которая меняется из двух мест - с клавы и мышки. соответственно isButtonPressed - это A, а status_mouse_key и status_space_key - это те самые A1, A2(_A1, _A2) из теоретической задачки.
Также я клоню к тому, что если не вводить фиктивных состояний, то логика кода остается прозрачной и четко поделенной на три части:
1. регистрация/отслеживание событий/изменений и т.д.
2. вычисление требуемого состояния
3. Приведение текущего состояния к требуемому.
соответственно при любых проблемах - можно четко сказать, а какая часть глючит, и что надо сделать, чтобы это исправить.
Причем результаты работы - всех этих трех модулей можно выдавать и пользователю.
т.е. пользователю можно показывать:
куда сейчас программа стремиться,
что она делает, чтобы обеспечить это стремление,
какое текущее состояние программой зарегистрировано.

Marinavo_0507

У тебя как раз есть один центральный метод, который вытягивает текущее состояние - соответственно все работает,
В дополнительном варианте - ты вводишь состояния, что сильно усложняет программу.
вторую задачу, как и первую опять же намного проще решать без состояний
Вот ты и пришёл к функциональному программированию.
Заметим, что в лоб преобразовывать программу может быть крайне неэффективно - программа 'a, скажем, на каждый чих проверяет состояние всех источников, а если их тысячи-миллионы? Придётся тогда переделывать, причём полностью вручную. Переделаешь неправильно - только время потратишь, а выгоды не получишь. А почему, должен был спросить ты, программирование должно быть таким сложным? А вот опять скажу, что не знаю.

Dasar

> Вот ты и пришёл к функциональному программированию.
я от него никогда и не уходил.
я только всегда говорю, что текущие ФЯ очень далеки от народа: в том смысле, что они скорее являются научными разработками, чем закончеными продуктами, пригодными для профессионального использования.
> Придётся тогда переделывать, причём полностью вручную.
почему вручную?
такой перевод невозможно формализовать? или просто нет готового инструмента для этого?

rosali

ошибка - core dumped - совсем не адекватная (причем даже у профессиональных программистов:
1. такая ошибка довольно часто встречается
2. все что можно ответить на вопрос "а почему программа так вылетела" - это только пожать плечами
3. почти не видел программ, которые бы совсем не вылетали по одной из таких ошибок, особенно в условиях стресса
)
ошибка - null pointer с номером строки и call stack-ом - уже почти совсем адекватная, и почти сразу позволяет выявить причину
ps
но еще лучше - если бы в тексте ошибки сразу бы указывалось, какая переменная ссылается в никуда.

Наверное ты хотел сказать segfault, потому что при core dumped нужно не пожимать плечами, а загрузить эту корку в отладчик и узнать и про null pointer, и номер строки, и стек и еще много чего, намного больше чем может донести исключение, включая имя переменной.

Dasar

И что ты собираешься увидеть, например, вот при такой ошибке?

struct TreeNode
{
PItem Childs[3];
PNode Next;
};
struct Item
{
};
void main
{
TreeNode node = new TreeNode;
node.Next = new TreeNode;
for (int i = 0; i <= 3; ++i)
node.Childs[i] = new Item;
//вот здесь все навернется
for (int i = 0; i<= 3; ++i)
node.Next.Childs[i] = new Item;
}

Marinavo_0507

> я от него никогда и не уходил
тогда, конечно, я возьму назад свои слова, что ты не умеешь справляться с алиасами
они верны в отношении правоверных ООшников, а не еретиков
> я только всегда говорю, что текущие ФЯ очень далеки от народа
Java, с которой в мейнстрим пришли хвалёные сборка мусора + строгая типизация (комбинация, которую потом m$ гордо назвали "управляемым кодом", так что даже в название треда попало тоже в начале (по крайней мере 1.x) была не более чем забавной игрушкой, которая продвинулась лишь благодаря одному killer application (анимированные картинки в www) + непредставимо огромные затраты на рекламу
> почему вручную?
ты же делаешь это вручную
почему ты считаешь, что сборку мусора и проверку типов должна делать платформа, а вот такие преобразования кода (которые я так и не знаю, как назвать правильно, легче коммутативную диаграмму нарисовать нормально делать руками?
по-моему, гордое название "управляемый код" без таких преобразований - не заслужено

Dasar

> вот такие преобразования кода (которые я так и не знаю, как назвать правильно, легче коммутативную диаграмму нарисовать нормально делать руками?
я полностью считаю - что вот такое преобразование кода - должно делаться автоматически.
именно - поэтому я считаю - что текущие ФЯ - это не более, чем игрушки, т.к. даже для своей основной задачи - они не предлагают готового решения.

Ivan8209

Оно и так делается автоматически.
Или про какое преобразование ты говоришь?
SML ругается на то, что рассмотрены не все случаи.
---
...Я работаю антинаучным аферистом...

Dasar

> Или про какое преобразование ты говоришь?
по функциональной модели или по декларативной модели - построить, например, событийную модель

Marinavo_0507

такое как раз бывает
осталось только потребовать это в виде продукта сегодня, как автоматическое управление памятью, и как строгую типизацию
ну можно ещё подождать, пока добрый дядя билл сам догадается

Dasar

> такое как раз бывает
понятно, что где-то как лаборатная разработка - это бывает.
но нужен же именно готовый продукт, а не лабораторная разработка....
а вот именно готовых продуктов и не видно.

rosali

Ну и при чем тут null pointer?
Пользуйся вместо массивов векторами или возьми из boost-а auto_array или как его там... А в месте критичном по производительности пиши внимательней. Ява же в принципе не позволяет отказаться от проверки на range, что хорошего? И вообще неужели контроль за памятью так помогает? В программах всегда есть какие-то внутренние инварианты, которые могут нарушаться. Работаешь скажем с деревом, везде в коде предполагается что оно действительно дерево, а вдруг раз и какой-нибудь ошибочный код взял и в этом дереве циклов понаделал. Обход дерева теперь ломается на stack overflow, ну и как тебе помогут твои exception-ы? Ты сможешь понять, что дерево зациклилось, а в каком месте это случилось не сможешь. Дурацкая какая-то иллюзия что язык способен защитить плохого программиста, разве что он должен быть алгоритмически неполным, как регулярные выражения например.

Ivan8209

> а вот именно готовых продуктов и не видно.
Если бы всегда были готовые решения, нужны были бы программисты?
Кроме того, это внутренняя задача программистов, как облегчить себе работу.
Кому надо, тот пользуется лабораторным проектом собственной подпольной разработки.
---
...Я работаю антинаучным аферистом...

Dasar

> Пользуйся вместо массивов векторами или возьми из boost-а auto_array или как его там... А в месте критичном по производительности пиши внимательней
какая-разница - вот тебе баг на stl

for (Items::iterator it = items.begin; it != items.end; ++it)
{
DoSomething(it);
}
void DoSomething(Items::iterator it)
{
if (it->IsBadItem
items.remove(it);
}

> Дурацкая какая-то иллюзия что язык способен защитить плохого программиста, разве что он должен быть алгоритмически неполным, как регулярные выражения например
Хороший язык - способен защитить модуль хорошего программиста, от модуля плохого программиста.
В C#/Java-е такой защитой является

try
{
ВыполнитьМаленькийДополнительныйБантик;
}
catch(Exception exc)
{
Trace.Write(exc);
}

В C/C++/Паскале - такой защиты - нет, и один плохо-написанный маленький бантик - отлично валит любую хоть сколько угодно хорошо написанную программу.

Dasar

> Если бы всегда были готовые решения, нужны были бы программисты?
так, о готовых решения, вообще, никто не говорит - это уж совсем недостижимая вещь.
Речь идет о готовых кубиках, из которых уже можно строить какие-то сложные конструкции.
> Кому надо, тот пользуется лабораторным проектом собственной подпольной разработки.
и что в этом хорошего?
это все равно, что хирург сам себе бы делал скальпели...

Dasar

> Ну и при чем тут null pointer?
> Пользуйся вместо массивов векторами или возьми из boost-а auto_array или как его там...
Думай...
Речь идет, вообще, о невалидных указателях, а не только о нулевых указателях.
И речь как раз о том, что в C#/Java самая страшная ошибка с неправильными указателями (ссылками) - это null pointer exception.
В C/C++/Паскале - при проблемах с указателями - мы получаем целый букет проблем: core dumped, null pointer exception, порча данных и т.д.
ps
Давай поступим проще, и постараемся уйти от пустого теоретического базара.
Ошибку в managed code - я готов найти (выявить сценарий проявления и место проявления) простую ошибку в течении часа, сложную часов за 8.
за 20$ в час меня можно уговорить такой работой заняться.
Соответственно оценка стоимости сверху одной ошибки - 20 - 160$.
За сколько времени и за какие деньги ты готов взяться за исправление ошибки core dumped в C/C++?
Я даже готов проверить твои слова, у меня как раз есть на примете несколько ошибок, которые проявляются в нескольких программ, написанных разными людьми.

bleyman

А ты не гонишь насчёт бага в стл?
И вообще - к чему это?
Видишь ли, итераторы относятся исключительно к стандартной библиотеке и в полном объёме переползли в шарп/жаву. foreach в принципе эквивалентен такому фору как ты написал, только короче.
И, соответственно, если посмотреть внутрь стандартных коллекций, можно увидеть, как в них реализованы итераторы. В частности, кстати, там всегда есть один мега-счотчик, который запоминается в итераторе при создании, инкризица каждый раз при доступе в коллекцию на запись, и ассертится равенство запомненного и текущего значений при доступе через итератор. Если в стл этого не делается - проблема с авторами стл, а не с разработчиками языка во-первых, и добавить такую проверку дело приблизительно получаса во-вторых.

bleyman

Трай-котч в с++ тоже есть, кстати.
Другое дело, что метод "выполнить маленький бантик" на шарпе может убить только то, что ты ему дашь, а на плюсах - что угодно =)

Dasar

> В частности, кстати, там всегда есть один мега-счотчик, который запоминается в итераторе при создании, инкризица каждый раз при доступе в коллекцию на запись, и ассертится равенство запомненного и текущего значений при доступе через итератор.
думать тоже лень?
какой-нафиг мегасчетчик, например, в итераторе поверх списка?
там обычный указатель на текущий элемент.
что пройзойдет, если этот элемент грохнут? правильно, обращение по невалидному поинтеру.
похожая ситуация и с вектором, но более хитрая.
что произойдет с итератором, если вектор (например, при добавление или удалении элементов) захочет переаллоцироваться? правильно, опять обращение по невалидному поинтеру.

bleyman

В итераторе поверх списка ещё может храниться указатель на голову списка, а точнее на сам объект "список".
Ещё есть подозрение, что в Boost проблема с реаллоком всё-таки решена.

Dasar

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

Marinavo_0507

хирурги отлично разрабатывают себе инструменты для новых видов операций

Dasar

> хирурги отлично разрабатывают себе инструменты для новых видов операций
проектируют или вытачивают?

bleyman

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

Ivan8209

Как ты себе представляешь кубик, перелопачивающий исходный текст всей программы?
Хорошего в этом то, что каждый использует средство,
соответствующее его задаче и устраивающее его.
Ты думаешь, что когда не было промышленных приборов,
никто ничего не делал?
Или что хирург не должен делать операции самодельным скальпелем только потому,
что последние не изготовляют в (полу)промышленных условиях?
---
...Я работаю антинаучным аферистом...

Marinavo_0507

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

Dasar

специализацию уже отменили?

Dasar

> Как ты себе представляешь кубик, перелопачивающий исходный текст всей программы?
нормально себе представляю. это ничем не сложнее, чем тот же GC, который тоже в некотором роде перелопачивает всю программу.
можно еще вспомнить такое модное слово - как АОП.
> Ты думаешь, что когда не было промышленных приборов,никто ничего не делал?
умеем видеть только черное и белое?
Где шла речь о том - что никто ничего не делает?
шла речь о том - что такая-то задача пока делается на коленке - соответственно качество решения данной задачи в промышленных масштабах, в целом, получается никакое.

Dasar

> не знаю, как в бусте реализованы умные пойнтеры. Но вообще я не вижу причин, мешающих написать на плюсах сборщик мусора и всё такое, причём так, чтобы все продолжало выглядеть вполне прозрачным. Там же можно вообще все операторы оверлоадить, включая даже dereference, плюс ещё макрогенератор присутствует.
и что дальше? например, вместо 6% ошибок стало 1% - это качественный скачок?
это же все игрушки. ну поигрались мы в эти игрушки, дальше зацепили новый модуль - и все стало валиться.
или мы сами все-таки допустили ошибку, например, передав свой умный указатель - модулю, который про умные указатели ничего не знает и т.д.

rosali

ВыполнитьМаленькийДополнительныйБантик;

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

bleyman

Хохохо.
Как будто вызывая из шарпа плюсовую дллку/ансейф код программист чувствует себя жутко уверенно и сухо.
Как будто винформы не умеют падать загадочным образом. Никогда не пробовал вызывать Application.EnableVisualStyles?

Dasar

> Ну допустим этот бантик банально завис, что дальше?
Thread.Abort
ps
но важнее - что класс ошибок приводящий к работе с невалидными указателями, где-то на два-три порядка более распространен, чем класс ошибок приводящий к зацикливанию.

Dasar

> Как будто вызывая из шарпа плюсовую дллку/ансейф код программист чувствует себя жутко уверенно и сухо
те модули - которые делают это - как раз обычно уже и не бантики.

bleyman

Вообще это я к тому, что на плюсах можно написать фреймворк, обеспечивающий практически полный аналог managed code, с умными пойнтерами, рейндж-чекингом, GC етс. Насколько я понимаю, Boost именно про это, не знаю, правда, насколько им удалось.
При этом твой вопрос - "а что будет, если код под этим фреймворком вызовет код не под ним?" - абсолютно аналогичен вопросу "а что будет, если safe-шарповый код вызовет unsafe или native код?", и ответ совпадает полностью.
Я вижу единственную разницу - в шарпе есть code access sequrity что-то там, которое позволяет в процессе подгрузки дллки явно потребовать её безопасности. Таким образом программеры неявно ориентируются в сторону написания safe кода.
Обратная сторона медали - правильное взаимодействие с native кодом в шарпе 1.1, например, было крайне усложнено, зато присутствовали крайне богатые возможности по реализации неправильного взаимодействия: забыть сказать fixed, не использовать Marshal.AllocHGlobal там где нужно, забыть про GC.KeepAlive (к слову, я до сих пор так и не знаю правильного метода работы с IntPtr хэндлами, так чтобы деструктор не вызвался в самый ответственный момент - неужели действительно GC.KeepAlive(this) в конце каждого метода писать?). Я ещё не смотрел во второй фреймворк - там, наверное, жизнь немного полегче, но возможностей для злоупотребления всё равно много скорее всего.

Dasar

> При этом твой вопрос - "а что будет, если код под этим фреймворком вызовет код не под ним?" - абсолютно аналогичен вопросу "а что будет, если safe-шарповый код вызовет unsafe или native код?", и ответ совпадает полностью.
есть тонкое, но очень важное "но"...
межбиблиотечный стык
при реализации на C++ до сих пор по стандарту де факту - является "опасным" (т.е. все указатели и т.д. - обычные, а не smart).
под .Net - весь межбиблиотечный обмен - по стандарту - managed.
Соответственно весь "опасный" код локализован в тонких, широкоиспользуемых (и соответственно - широкопротестированных) оберточках.
> забыть сказать fixed
с какой целью, вообще, ты хочешь fixed использовать?
> не использовать Marshal.AllocHGlobal там где нужно
это понятно.
> забыть про GC.KeepAlive (
опять же - с какой целью ты его хочешь использовать?

Marinavo_0507

> специализацию уже отменили?
только для тех, кто полностью не читает то, на что отвечает

Marinavo_0507

> это ничем не сложнее, чем тот же GC, который тоже в некотором роде
> перелопачивает всю программу.
к сожалению, если каждый подобный "кубик" будет требовать нового языка, то не очень-то из них можно будет что-то собрать
а уж если хочется поддержки дяди билла, то вообще кошмар

Maurog

Ты бы еще посоветовал
 
break;


> Ну допустим этот бантик банально завис, что дальше?
Thread.Abort
ps
но важнее - что класс ошибок приводящий к работе с невалидными указателями, где-то на два-три порядка более распространен, чем класс ошибок приводящий к зацикливанию.

bleyman

> при реализации на C++ до сих пор по стандарту де факту
Хохо. А куда тебе впился тот стандарт? Порождай отдельный процесс, вызывай из него библиотечные функции, общайся с ним через пайпы/шаред мемори.
Что дотнетовские ссылки, что умные указатели всё равно через интероп не пролезут. Максимум, на что ты можешь рассчитывать - прокси с подсчётом ссылок.
> с какой целью, вообще, ты хочешь fixed использовать?
Чтобы GC не подвинул тот кусок памяти, указатель на который я отдал внешнему коду.
>> забыть про GC.KeepAlive (
>опять же - с какой целью ты его хочешь использовать?
1) Чтобы GC не сожрал мой делегат, который я отдал внешнему коду в качестве евент хендлера.
2) Ффтыкай: http://blogs.msdn.com/cbrumme/archive/2003/04/19/51365.aspx
Если ты в нестатическом методе доступаешься до this.hWnd (например) (которая IntPtr и после этого к своим полям ни разу не обращаешься, а какой-нибудь чувак, который этот метод вызвал, тоже к твоему объекту ни разу не обращается, то строго говоря, после того, как ты положил этот инт на стек, может сразу вызваться деструктор - прям в середине метода. В деструкторе ты, конечно, хэндл освободишь. А потом GC вернёт управление основному треду, который снимет со стека инт и передаст его в какой-нибудь p/invoke, ну и словит хз что - но это не всегда, а только если очень повезёт с моментом вызова GC.
Мне удалось добиться описываемого эффекта при помощи вызова GC.Collect в нужном месте.
Часть проблем решает структурка HandleRef (кажется но когда я как-то очень сильно над этим задумался, я понял, что она решает не все проблемы.
p/invoke в .NET обло, стозёво и лайай.
Левые пойнтеры сосут у рандомного мусоросборщика по сложности дебага, ИМХО. Хотя бы потому, что программеру вряд ли в принципе удастся повторить ситуацию "а я вот тут час что-то делал, потом сказал сохранить, потом оно что-то стало делать, а я пока альт-табнулся, а памяти у меня 128 метров, ну и короче оно мне сказало Invalid File Handle и ничо не сохранило".

Dasar

> Хохо. А куда тебе впился тот стандарт? Порождай отдельный процесс, вызывай из него библиотечные функции, общайся с ним через пайпы/шаред мемори.
ты в виртуальном мире что ли живешь?
кто за это платить будет?
> Чтобы GC не подвинул тот кусок памяти, указатель на который я отдал внешнему коду
нафига interop-у отдавать .net-память? ради мифической скорости?
> 1) Чтобы GC не сожрал мой делегат, который я отдал внешнему коду в качестве евент хендлера.
добавить его в static-коллекцию, и не мучаться
> Если ты в нестатическом методе доступаешься до this.hWnd (например) (которая IntPtr и после этого к своим полям ни разу не обращаешься, а какой-нибудь чувак, который этот метод вызвал, тоже к твоему объекту ни разу не обращается, то строго говоря, после того, как ты положил этот инт на стек, может сразу вызваться деструктор - прям в середине метода. .
afaik, здесь не так все просто..
на this есть ссылка в стеке, GC оставляет в живых объекты - на которых есть ссылки из static-а, из локальных переменных и стека.

Dasar

мне самое главное не понятно.
ты хочешь серьезно поспорить, что на C/C++ разработка будет дешевле, чем на .Net/C#?
зы
на основе своего опыта - твердо скажу, что разработка C# приложения в разы дешевле:
в первую очередь - за счет намного меньшего времени на отладку, и обеспечения устойчивости приложения
во вторую - за счет более быстрого вхождения/обучения новых участников, в том числе со средней/плохой квалификацией в области программирования
в третьих - за счет меньших затрат на всякую чихню (разделение на h/cpp файлы, двухпроходность, отсутствие модулей и т.д.)

Dasar

> памяти у меня 128 метров, ну и короче оно мне сказало Invalid File Handle и ничо не сохранило".
как я уже писал, для избегания таких ситуаций - необходимо использовать подход - неизвестных ситуаций всегда в разы больше, чем известных, поэтому код должен по максимуму адекватно работать даже в случае непредвиденного поведения.
применение этой стратегии можно организовать в .net/с#-е и очень тяжело в С/C++.

Ivan8209

Я не знаю, про какую именно сборку мусора ты говоришь,
там есть, по-хорошему, только два подхода:
а) ты сам пишешь поддержку сборки мусора
и сам же заморачиваешься соблюдением соглашений,
всеми своими запираниями, увеличением счётчика ссылок,
помечением и прочими извращёнными фантазиями;
б) выбираешь другой язык, поддерживающий сборку мусора.
В первом случае, ты сам анализируешь свою программу вручную,
потому что нет синтаксических соглашений, помогающих перелопачиванию.
Я не верю в то, что качество промышленных приборов однозначно выше кустарных.
Скорее даже наоборот.
---
"Верь сводке погоды, но доверяй --- интуиции.
Будь особенно бдителен, когда всё хорошо и нет поводов для тревоги."

bleyman

>> на this есть ссылка в стеке, GC оставляет в живых объекты - на которых есть ссылки из static-а, из локальных переменных и стека.
Чуве, сходи по ссылке, скопируй тот код в файл test.cs, напиши в консоли csc test.cs, потом test.exe.
Не остаётся this ни на стеке, ни в локальной переменной, по крайней мере в компиляторе из 1.1 фреймворка.
----
Нука расскажи, как ты будешь максимально эффективно справляться с тем, что в середине сохранения большого файла у некоторых твоих пользователей выскакивает такой эксепшен? Я вижу всего два варианта:
1) Ты случайно наткнёшься на человека, который знает, как правильно работать с IntPtr хэндлами, объяснит тебе, и ты долго и с удовольствием будешь проверять все свои обёртки над внешними ресурсами.
2) Ты уберёшь CloseHandle из всех деструкторов. Отличный выход!
----
>> добавить его в static-коллекцию, и не мучаться
Хохо. Видишь ли, мы тут ОШИБКИ обсуждаем.

Marinavo_0507

> Я вижу всего два варианта:
3) Убрать все деструкторы, всё зло от них.
годится?

bleyman

>> ты хочешь серьезно поспорить, что на C/C++ разработка будет дешевле, чем на .Net/C#?
Неа. Я хочу поспорить с тем, что managed code является качественным прорывом по сравнению с С++.
Да, плюсы позволяют использовать умные пойнтеры, а шарп позволяет использовать обычные (как-то очень фигово, правда. Вот например, не знаешь ли ты, где можно прочитать, что происходит на самом деле, когда я получаю указатель на массив или на строку? Где там длина хранится, например) - ну так вот, это разница в подходе, конечно, но не качественная ИМХО.

bleyman

А где CloseHandle вызывать-то? Или фиг с ними, с хэндлами, пусть висят?
Или обязать оформлять каждое открытие-доступ-закрытие к файлу в using, а где не получится (например, доступ осуществляется не непрерывно) оформлять каждый доступ в try-finally {file.Dispose} ?
К тому же учти - это всего лишь один из примеров проявления забавных свойств p/invoke. Я довольно долго работал с managed DX, и могу честно сказать: к концу прошлой весны его разработчикам всё ещё не удалось получить что-то стабильное (это за сколько лет получается - два, три?).

Marinavo_0507

Или обязать оформлять каждое открытие-доступ-закрытие к файлу в using, а где не получится (например, доступ осуществляется не непрерывно) оформлять каждый доступ в try-finally {file.Dispose} ?
Да, по-старинке, ручками.
Всё равно ж не гарантируется, что GC их соберёт вовремя. А кончится лимит открытых файлов - будет обидно (кроме файлов, есть и другие ресурсы, где ещё обиднее может быть).

Marinavo_0507

Я довольно долго работал с managed DX, и могу честно сказать: к концу прошлой весны его разработчикам всё ещё не удалось получить что-то стабильное (это за сколько лет получается - два, три?).
А что у MS сразу становилось стабильным?
Тем более, глупо этого ожидать от игровых шняг.

bleyman

>> А что у MS сразу становилось стабильным?
Там была очень, очень сильная нестабильность.
При том, что единственное, по сути, что требовалось от разработчиков - написать managed врапперы вокруг сотни где-то уже написанный DX-овых классов. Ну вот не удалось. Заметь, это не левые люди, а микрософтовцы, так что если им что-то непонятно, они бы довольно быстро могли всё понять.
>> Тем более, глупо этого ожидать от игровых шняг.
Насколько я понял, в Висте графическая подсистема будет одна - авалон, он же - directX 10. С другой стороны, донНЕТ будет основной платформой для приложений. Так что получить managed обёртку для ДХ им довольно важно, не правда ли?

Marinavo_0507

Насколько я понял, в Висте графическая подсистема будет одна - авалон, он же - directX 10.
Win32-приложения не будут работать?

Helga87

Avalon = Windows Presentation Framework - оконная подсистема, которая будет доступна в Windows XP, Windows 2003 и Windows Vista. Win32 в Висте останется. Но под Avalon можно будет писать только на .net.
Windows Graphics Foundation = ~DirectX 10 - то, что будет лежать под Авалоном и Win32-окошками, позволяя рендериться с использованием графического ускорителя.
Ну и, Avalon != DirectX 10, конечно

Helga87

Будут. В MS же не до конца идиоты сидят

Dasar

> Чуве, сходи по ссылке, скопируй тот код в файл test.cs, напиши в консоли csc test.cs, потом test.exe.
там бред какой-то написан, а не тестовый пример...
ps
проверил, и правда бред написан.

Dasar

Лично ты можешь привести пример, который показывает, что есть проблема с освобождением handle-ов?
или ты лишь руководствуешься базарными сплетнями?

bleyman

using System;
using System.Threading;
using System.Collections;
namespace GCTest
{
public class EnvironmentEmulator
{
private static SortedList openHandles = new SortedList;
private static int nextHandle = 1;
public static int GetHandle
{
int handle = ++nextHandle;
openHandles.Add(handle, null );
return handle;
}
public static void ReleaseHandle(int handle)
{
openHandles.Remove(handle);
}
public static bool OperateOnHandle(int handle)
{
GC.Collect; // It can happen any time, for example here.
return openHandles.ContainsKey(handle);
}
}
public class MyResource : IDisposable
{
private int handle;
private bool disposed = false;
public void DoSomething
{
Console.WriteLine("Entering A.DoSomething");
Console.WriteLine("Handle valid: " + EnvironmentEmulator.OperateOnHandle(handle;
Console.WriteLine("Exiting A.DoSomething");
}
public MyResource(int handle)
{
Console.WriteLine("A..ctor");
this.handle = handle;
}
public void Dispose
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if(!this.disposed)
{
if(disposing)
{
// No managed resources
}

EnvironmentEmulator.ReleaseHandle(handle);
handle = 0;
}
disposed = true;
}
~MyResource
{
Console.WriteLine("A..Finalize");
Dispose(false);
}
}
public class MainClass
{
public static void Main
{
bool something = true;
if ( something )
{
MyResource res = new MyResource(EnvironmentEmulator.GetHandle;
res.DoSomething;
}
}
}
}

C:\Programming\GCTest>csc Class1.cs
Microsoft (R) Visual C# .NET Compiler version 7.10.6310.4
for Microsoft (R) .NET Framework version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002. All rights reserved.
C:\Programming\GCTest>Class1.exe
A..ctor
Entering A.DoSomething
A..Finalize
Handle valid: False
Exiting A.DoSomething
C:\Programming\GCTest>

Marinavo_0507

Деструкторы в языках с GC - глупая идея.
Если не пользоваться ими, есть проблемы?

bleyman

Когда мы с Красиным это изучали, выяснилось, что на разных машинах получаются разные ответы, причём закономерность уловить не удалось.
В данном случае ошибка ясна - используя инт вместо ссылки я обманываю GC. Однако я не очень понимаю, что следует использовать вместо IntPtr при общении с внешними дллками.

bleyman

А хэндл где освобождать?
Принудительно вызывать Dispose ? А в чём тогда понт GC вообще, если мне всё равно приходится руками контролировать время жизни всех ресурсов?

Marinavo_0507

> А в чём тогда понт GC вообще, если мне всё равно приходится руками
> контролировать время жизни всех ресурсов?
Не всех. Память таки освобождается сама. Для контроля других ресурсов GC в текущем виде не пригоден.

bleyman

Я уж не говорю о том, что приведённый выше код целиком и полностью соответствует микрософтовским гайдлайнам по написанию Dispose+Destructor, который, в частности, реализован в классе Form (или где-то выше по иерархии, не помню точно).

bleyman

Да нет, вполне пригоден.
Достаточно вставить в конец метода DoSomething кодовую строчку GC.KeepAlive(this). Только об этом мало кто знает =)

Marinavo_0507

Выше я объяснил, почему не пригоден.
А вставлять данный вызов компилятор мог бы и сам (с небольшой подсказкой это баг дизайна фреймворка походу.

bleyman

В ссылке по теме, которую я давал кучу постов назад и которую, судя по всему, никто так и не прочитал, чувак из Микрософта сказал, что ограниченность числа регистров в х86 архитектуре не позволяет эффективно распространить область "используемости" this до конца каждого нестатического метода. Я не очень понял, что именно он имеет в виду, но вообще верю.

Dasar

Меня всегда забавляет, как люди обижаются, когда выясняют, что сложные системы нельзя во всех мелочах контролировать.
Современная программа - это сложная система, потому что, как минимум, мы имеем пять агентов, которые управляют программой: программист, пользователь, ОС, GC и другое окружение (например, наличие электричества в розетке).
В текущих программах можно контролировать только лишь 10%, 5%, 1%, 0.1% "ситуаций", все остальное находится - вне контроля. - И это нормально, ничего в этом страшного нет.
Надо лишь писать программы так, чтобы:
1. вот эти 10% - 0.1% контроля были бы не абы где, а в ключевых точках. и при этом вот эти ключевые точки - должны, по минимуму, зависить от плохо контролируемого окружения.
2. у каждого приложения, модуля, класса, метода - был запас по прочности.
Ответ по существу на данный пример: используйте using/Dispose и будет вам счастье
ps
Могу привести пример похожей ошибки, где конфликт идет уже между программистом и агентом "другое окружение", а не между программистом и GC.

class MyClass
{
public void Load
{
using (StreamReader reader = new StreamReader("my.config"
{
data = reader.Read;
}
}
Data data;
public void Save
{
using (StreamWriter writer = new StreamWriter("my.config"
{
//если здесь кончится электричество, то мы опять же получим не рабочее приложение.
//особенно меня радуют приложения, которые открывают файл конфига на запись при старте,
//а закрывают в конце - по завершению приложения.
writer.Write(data);
}
}
}

Marinavo_0507

если здесь кончится электричество, то мы опять же получим не рабочее приложение
ещё более вероятна ситуация, когда ФС переполнена
тогда обнулить файл оно сможет, а записать что-то - уже далеко не факт
в отличие от электричества, с такими косяками я на практике сталкивался
и никакая хитроплатформа не помогает, головой надо думать

bleyman

Про контроль - всё понятно, программа не в вакууме висит. Когда я писал под микроконтроллеры, я вообще имел хорошую привычку обкладывать все данные во внешней памяти контрольными суммами.
Ответ по существу на данный пример: используйте using/Dispose и будет вам счастье
Эх. Ты, видимо, забыл, о чём речь вообще. Я тебе говорю: p/invoke во фреймворке сцуко опасный (в частности тем, что совершенно не выглядит опасным). Поэтому вот это твоё
есть тонкое, но очень важное "но"...
межбиблиотечный стык
при реализации на C++ до сих пор по стандарту де факту - является "опасным" (т.е. все указатели и т.д. - обычные, а не smart).
под .Net - весь межбиблиотечный обмен - по стандарту - managed.
Соответственно весь "опасный" код локализован в тонких, широкоиспользуемых (и соответственно - широкопротестированных) оберточках.
наглая ложь. ДотНетовский "безопасный" интероп гораздо опаснее плюсового "опасного".
Предложение обязывать _пользователей_ моего класса всегда вызывать Dispose мне кажется немножко издевательским. В десятый раз повторяю: GC.KeepAlive(this) в конце каждого метода решает все проблемы. Другое дело, что ты, например, об этом не знал, хотя вроде как специалист.

Dasar

> ДотНетовский "безопасный" интероп гораздо опаснее плюсового "опасного".
дык, interop как раз и не является стандартным межбиблиотечным стыком.
interop - это нестандартный стык с legacy-кодом.
в C++ - даже родные модули между собой стыкуются через обычные "опасные" указатели, а не через умные "безопасные" указатели.

Dasar

> В десятый раз повторяю: GC.KeepAlive(this) в конце каждого метода решает все проблемы. Другое дело, что ты, например, об этом не знал, хотя вроде как специалист
я этот метод знаю, но не держу в активной памяти, потому что в практических задачах - сложный pinvoke используется очень редко.
Оставить комментарий
Имя или ник:
Комментарий: