Здравствуйте, Sinclair, Вы писали:
S>А с каких это пор у нас CreateInstance противоположно по смыслу Release? Не пора ли заглянуть в словарь? S>Парой к CreateInstance была бы, очевидно, DeleteInstance. Парой к Release — Lock. А парой к AddRef (которая на самом деле парная к Release в Com — CreateInstance штука неспаренная) была бы RemoveRef.
К счастью, антонимы неоднозначны. К одному слову может существовать несколько противоположных. Скажем, в вашем же примере — почему DeleteInstance, а не DestroyInstance? Так что в словарь заглядывать рано.
Что парной к Release() является AddRef() я, естественно, знаю. Но ведь CreateInstance() вызывает AddRef(), разве нет? И "паттерн" использования COM-объекта чаще всего именно такой: создать по CreateInstance(), поработать с ним и освободить по Release().
Здравствуйте, Сергей Губанов, Вы писали:
MN>>Или вы утверждаете, что в обероне вы обойдётесь без последней проверки? Извините, в силу своего не очень маленького опыта в программировании не поверю в это!
СГ>Вы путаете. Цикл WHILE гарантирует лишь то, что выражение "str[i] != ch || str[i] != 0" будет ложным после его завершения (если он завершиться конечно когда-нибудь). Больше он ничего не гарантирует. То что это выражение само в свою очередь состоит из нескольких — совершенно другой вопрос.
Вы русский язык понимаете вообще? Вам были заданы простейшие вопросы, вы можете на них ответить предельно просто: да или нет.
1)
int i = 0;
while(str[i] != ch || str[i] != 0) i++;
if(str[i] == 0) // символ не найденelse// символ найден
Реализация подобного алгоритма на Обероне будет содержать проверку результата завершения в конце (и не надо дискуссий на тему, что строки в Обероне реализованы по другому): да или нет?
2) Можно подобный алгоритм в Обероне реализовать иным способом без проверки завершения в конце: да или нет?
3)
long fact = 1;
int i = 0;
for(i = 1; i < 10; i++) fact *= i;
if(i < 10)
{
// по какой-то причине цикл не выполнился до конца...
}
Вы всегда в C++ делаете подобную проверку на причину завершения в конце цикла, контекст которого вы контролируете и который не содержит явно вставленых команд прерывания: да или нет?
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Здравствуйте, faulx, Вы писали:
F>К счастью, антонимы неоднозначны. К одному слову может существовать несколько противоположных. Скажем, в вашем же примере — почему DeleteInstance, а не DestroyInstance? Так что в словарь заглядывать рано.
Потому, что антонимом к DestroyInstance является ConstructInstance.
F>Что парной к Release() является AddRef() я, естественно, знаю. Но ведь CreateInstance() вызывает AddRef(), разве нет?
Неважно, кто кого вызывает. Иначе мы так до чего угодно договоримся. От того, что CreateInstance вызывает парную к Release функцию, она сама парной не становится. F>И "паттерн" использования COM-объекта чаще всего именно такой: создать по CreateInstance(), поработать с ним и освободить по Release().
А какое отношение имеет паттерн использования COM объекта? В него обычно входит еще много других вызовов. У CreateInstance пары нет.
Теоретически, можно считать, что есть приватная DeleteInstance, которая вызывается из Release при достижении нулевого количества ссылок.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, faulx, Вы писали:
F>Что парной к Release() является AddRef() я, естественно, знаю. Но ведь CreateInstance() вызывает AddRef(), разве нет? И "паттерн" использования COM-объекта чаще всего именно такой: создать по CreateInstance(), поработать с ним и освободить по Release().
Спасибо хоть "чаще всего", а не "всегда"...
Не знаю как у кого, но лично мне практически при каждом серьёзном использовании COM приходится несколько раз ручками вызывать AddRef() при передаче указателей на COM-объекты. Конечно, это не слишком актуально для "одноразовых" объектов, но когда объект глобальный и длительного использования — приходится для надёжности. Только так есть гарантия, что все экземпляры классов и все потоки не получат "мусор", уже удалённый кем-то.
А в конце работы, кстати, в отладочной версии всегда ставлю проверку и вывод значения, возвращаемого Release(). Вот такое оно бесполезное.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
WARNING: expression "to_be || !to_be" is always true
Здравствуйте, Mr. None, Вы писали:
A>>P.S. Mr. None, только на мою фразу про "никто не понимает" обижаться не нужно Сгоряча сказалось.
MN>В следующий раз досчитайте до 10, прежде чем горячиться и перечтите всю ветку дискуссии.
for (int i = 1; i <= 10; i++) printf("%i\n", i);
MN>Отличий между указателем (именно указетелем, а не объектом, на который он указывает) и стековым объектом POD-типа нет. Потому что указатель такой же POD-тип, подчинённый тем же правилам поведения.
Верно. Но это же УКАЗАТЕЛЬ.
А у меня, кстати, вообще не компилится никакой пример с пропущенным стековым объектом. Студия 7.1 слопала только примитивный тип (int и тот самый указатель), да и то изматерилась warning-ами и assert-ами. На любой класс, даже на такой:
class a
{
a() {}
~a() {}
}
Ругалась ошибками "initialization of 'two' is skipped by 'goto lbl'".
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
WARNING: expression "to_be || !to_be" is always true
Здравствуйте, Пацак, Вы писали:
П>Детский сад, честное слово. Вы таки объяснить можете, чем одно от другого отличается? Про "выполняется или нет следующая команда" рассказывать не надо: вот здесь, например, она вполне себе выполняется в обоих случаях: П>
П>LOOP
П> WHILE 1<2 DO
П> IF 3<4 THEN EXIT END
П> END
П>END
П>A := B;
П>
Тяжелый случай. Бывает хуже но реже. Объясняю на пальцах A := B; — это инструкция следующая после LOOP она выполняется потому, что EXIT завершает цикл LOOP.
LOOP
WHILE 1<2 DO
IF 3<4 THEN EXIT END
END;
B := C
END;
A := B
Следующей после цикла WHILE инструкцией будет B := C и вот она-то никогда не выполнится, так как этот цикл WHILE никогда не будет завершен. Он будет прерван LOOP-ным EXIT-ом.
P. S. break — завершает, а не прерывает. Прерывает, например, return.
Здравствуйте, Amidlokos, Вы писали:
MN>>Отличий между указателем (именно указетелем, а не объектом, на который он указывает) и стековым объектом POD-типа нет. Потому что указатель такой же POD-тип, подчинённый тем же правилам поведения.
A>Верно. Но это же УКАЗАТЕЛЬ.
И что?
A>А у меня, кстати, вообще не компилится никакой пример с пропущенным стековым объектом. Студия 7.1 слопала только примитивный тип (int и тот самый указатель), да и то изматерилась warning-ами и assert-ами. На любой класс, даже на такой:
A>Ругалась ошибками "initialization of 'two' is skipped by 'goto lbl'".
Здравствуйте, Mr. None, Вы писали:
MN>А теперь к сути дискуссии, поскольку вы, судя по всему, её не поняли. Кодт утверждал, что правильный компилятор не позволит перескочить (goto) через определение локальных переменых. Однако, согласно пункту 6.7/3 стандарта C++ — это не так:
MN>It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program
MN>that jumps77) from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is illformed unless the variable has POD type (3.9) and is declared without an initializer (8.5).
MN>[Example:
MN>void f()
MN>{
MN> // ...
MN> goto lx; // illformed: jump into scope of a
MN> // ...
MN>ly:
MN> X a = 1;
MN> // ...
MN>lx:
MN> goto ly; // OK, jump implies destructor
MN> // call for a followed by construction
MN> // again immediately following label ly
MN>}
MN>—end example]
То есть, насколько я понял,
void foo() {
...
goto after_x; // нет проблем: x не инициализируется
.../*1*/int x;
.../*2*/
after_x:;
...
goto after_y; // а вот за это - бьём по пальцам
...
int y = 123;
...
after_y:;
...
}
И в этом есть своя правда: С/С++ позволяет иметь дело с неинициализированными POD-переменными, так что, достигнув точки after_x прямым путём (через точку объявления x), мы имеем право на мусор. То есть, это не отличается от
void foo() {
int x; // объявили переменную в начале функции - как это принято в С
...
goto after_x;
.../*1*/
// начиная с этого места, x упоминается в коде
.../*2*/ // возможно, где-то здесь мы делали присваивание
after_x:;
...
}
П>step := get_step();
П>i := 0;
П>LOOP
П> IF i >= max_level THEN EXIT END;
П> sound_level(i);
П> i := i + step;
П> IF manual_interrupt() THEN EXIT END;
П>END
П>
Вы забыли проверить истинность выражения "step > 0"
step := GetStep();
IF (step > 0) & (maxLevel > i0) THEN
i := i0;
REPEAT SoundLevel(i); INC(i, step) UNTIL (i >= maxLevel) OR ManualInterrupt()
END
Здравствуйте, Mr. None, Вы писали:
MN>Вы русский язык понимаете вообще? Вам были заданы простейшие вопросы, вы можете на них ответить предельно просто: да или нет.
Здравствуйте, Amidlokos, Вы писали:
MN>>Отличий между указателем (именно указетелем, а не объектом, на который он указывает) и стековым объектом POD-типа нет. Потому что указатель такой же POD-тип, подчинённый тем же правилам поведения.
A>Верно. Но это же УКАЗАТЕЛЬ. :???:
т.е. объект POD-типа. Что за низкопоклонство перед указателями? :)
A>А у меня, кстати, вообще не компилится никакой пример с пропущенным стековым объектом. Студия 7.1 слопала только примитивный тип (int и тот самый указатель), да и то изматерилась warning-ами и assert-ами. На любой класс, даже на такой:
A>
A>class a
A>{
A>a() {}
A>~a() {}
A>}
A>
A>Ругалась ошибками "initialization of 'two' is skipped by 'goto lbl'".
Потому что этот класс — не POD-тип, так как имеет определенный пользователем конструктор.
Вот если ты его объявишь как-нть так:
Согласен, что выбрал не очень подходящее слово для обозначения смысла того что я назвал там термином "прерывание цикла". Более правильного по смыслу слова я тогда не придумал. Впрочем, не придумал и сейчас.
Если Вам хочется пользоваться буквальным переводом слова break, то понимайте под ним прерывание текущей итерации и завершение цикла.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Mr. None, Вы писали:
MN>>А теперь к сути дискуссии, поскольку вы, судя по всему, её не поняли. Кодт утверждал, что правильный компилятор не позволит перескочить (goto) через определение локальных переменых. Однако, согласно пункту 6.7/3 стандарта C++ — это не так: MN>>...
К>То есть, насколько я понял, К>... К>И в этом есть своя правда: С/С++ позволяет иметь дело с неинициализированными POD-переменными, так что, достигнув точки after_x прямым путём (через точку объявления x), мы имеем право на мусор. То есть, это не отличается от К>...
Абсолютно верно . Но сермяжная правда жизни такова, что например MS VC, включая VC 7.1, на эту самую приписку относительно is declared without an initializer благополучно забивает и позволяет перескакивать через определения скалярных, вещественных типов и указателей, даже если они имеют иницилизатор. Как пример перескакивание через TestClass *ptr = new TestClass();. В итоге ptr мы видим, но забит он фигнёй и нет никакой возможности проверить был он проинициализирован или нет . Согласен, что это явное не соответствие стандарту, но поскольку этот компилятор сильно распространён с этим фактом приходится считаться . Именно с этим и было связано моё заявление, относительно того, что я не берусь предсказать, что будет если выполнить такой прыжок.
А в остальном вы правы — здравый компилятор такое не пропустит, а перепрыгивание скалярных типов без инициализаторов не приведёт ни к каким катострофическим последствиям... так что
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Здравствуйте, Mr. None, Вы писали:
MN>>Вы русский язык понимаете вообще? Вам были заданы простейшие вопросы, вы можете на них ответить предельно просто: да или нет.
СГ>Да.
СГ>(В смысле русский язык понимаю)
Вы как всегда в своём амплуа. Если ответы на вопросы угрожают вашей теории, вы на них не отвечаете... Вобщем продолжать дискуссию считаю абсолютно бесполезно. Потому что вы не умеете слушать и отвечать на вопросы аппонента. А всё остальное смысла не имеет.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
A>>Ругалась ошибками "initialization of 'two' is skipped by 'goto lbl'".
J>Потому что этот класс — не POD-тип, так как имеет определенный пользователем конструктор.
Не конструктор, а деструктор . Наличие конструктора не превращает класс в POD-тип:
Стандарт, 9.4
...A POD-struct is an aggregate class that has no nonstatic data members of type pointer to member, non-POD-struct,
non-POD-union (or array of such types) or reference, and has no userdefined copy assignment operator and no userdefined destructor...
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Тяжелый случай. Бывает хуже но реже. Объясняю на пальцах A := B; — это инструкция следующая после LOOP она выполняется потому, что EXIT завершает цикл LOOP.
Случай и правда тяжелый. А какая инструкция в этом коде следует за WHILE? Про END не вспоминать — это не инструкция, это признак конца теля цикла.
СГ>Следующей после цикла WHILE инструкцией будет B := C и вот она-то никогда не выполнится, так как этот цикл WHILE никогда не будет завершен. Он будет прерван LOOP-ным EXIT-ом.
Это-то понятно. Но вернемся к исходной задаче —
LOOP
WHILE bool DO
IF 3<4 THEN EXIT END
bool := false;
END;
END;
IF Not bool THEN print("We did it!");
Непосредственно после WHILE стоит проверка его условия на ложность. Условие не срабатывает. Таким образом в обероне можно создать условия, при которых после окончания (не суть важно — "завершения" или "прерывания") его условие все еще будет =TRUE, т.е. не глядя на код внутри и вокруг цикла полагаться на это, увы, нельзя. Равно как и в C++. Предвижу возражение "это в случае "прерывания" нельзя, а в случае "нормального" завершения — можно". Увы, нет:
WHILE random(0,1) > 0.5 DO
...
END;
IF random(0,1) <= 0.5 THEN print("We did it!");
В итоге — грабли ничем не лучше, чем в C++ с break'ом.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Вы забыли проверить истинность выражения "step > 0"
Без разницы, суть дела от этого сильно не изменится — в C++ я дописываю код, в обероне — переписываю его.
СГ>
{скип}
СГ> REPEAT SoundLevel(i); INC(i, step) UNTIL (i >= maxLevel) OR ManualInterrupt()
СГ>END
СГ>
Ма-а-аленькая тонкость. Если в моем коде maxLevel изначально = 0 (звук выключен), то цикл не выполнится ни разу. В вашем — выполнится один раз. То есть мы наблюдаем очередную подмену понятий.
Здравствуйте, Mr. None, Вы писали:
MN>>>Вы русский язык понимаете вообще? Вам были заданы простейшие вопросы, вы можете на них ответить предельно просто: да или нет.
СГ>>Да.
СГ>>(В смысле русский язык понимаю)
MN>Вы как всегда в своём амплуа. Если ответы на вопросы угрожают вашей теории, вы на них не отвечаете... Вобщем продолжать дискуссию считаю абсолютно бесполезно. Потому что вы не умеете слушать и отвечать на вопросы аппонента. А всё остальное смысла не имеет.
Я просто не отвечаю на вопросы ответы на которые и так очевидны, за исключением некоторых случаев (например сейчас). Собеседник должен это понимать и формулировать свои якобы вопросы не как вопросы, а как безусловные утверждения, повествования. Вместо якобы вопроса "В **** языке программирования 2 + 2 тоже равно 4. Вы можете ответить предельно просто Да или Нет?" надо писать безусловное утверждение "В **** языке программирования 2 + 2 тоже равно 4", не требующее какого-либо подтверждения. Ведь если это не так, то с большой вероятностью кто-то это сразу же опровергнет, но если это так, то экономя время и трафик ответа=подтверждения дано не будет.