Комментарии 79
НЛО прилетело и опубликовало эту надпись здесь
Угу. Мужики привыкли приведение типов писать как (int)b, т.е. в данному случае: (a)b.
+7
НЛО прилетело и опубликовало эту надпись здесь
Приведение типов должно бесить по умолчанию. C-style cast вместо заметного static_cast<> — тем более
+9
Задачка конечно веселая. И очередной раз как бы намекает нам что гибкость С и особенно C++ нужно использовать во благо, а не писать нечитаемый код.
+2
НЛО прилетело и опубликовало эту надпись здесь
А вы если случайно ложку дёгтя уроните в бочку с мёдом, тоже вот такой вот статьей разразитесь, что дескать мёд какой-то невкусный получился? :)
Это я к чему? К тому, что программист в любом случае должен быть аккуратным, независимо от того, следит за его косяками язык или нет. И уж не соглашусь, что std::string a() — классика, бред это, по рукам давать программисту прутом железным, чтобы неповадно было.
«Программа делает то, что вы ей сказали делать, а не то, что хотели бы, чтобы она делала.»
Это я к чему? К тому, что программист в любом случае должен быть аккуратным, независимо от того, следит за его косяками язык или нет. И уж не соглашусь, что std::string a() — классика, бред это, по рукам давать программисту прутом железным, чтобы неповадно было.
«Программа делает то, что вы ей сказали делать, а не то, что хотели бы, чтобы она делала.»
-2
Слово «подебачить » стало правильно понятым раза с 5го :)
+9
Прикольный стиль повествования :)
0
Честно говоря вот читал и ждал когда расскажут почему «1» а не «5»… Может я что-то все-таки не до конца понял?
0
очень просто, мы объявляем локальную переменную b, которая в scope main()'a используется вместо глобальной.
а так как b не инициализирована то туда попадает мусор
а так как b не инициализирована то туда попадает мусор
+1
просто мне кажется что стоило и написать что в результате мусор.
А вот то что всегда один и тот же результат — «1» — вот это плохо.
Помню когда-то была даже история от кого-то из Microsoft о том, как они убирали кусок 100% неиспользуемого кода и продукт (вроде офис) валился. Разкоменчивали — работал. Как оказалось «мусор» брался именно с того куска, который не использовался, и на результате этого мусора была накручен используемый функционал.
Так что детерминированный «мусор» гораздо опасней случайного.
В исходном коде лучше бы написали:
или типа того
А вот то что всегда один и тот же результат — «1» — вот это плохо.
Помню когда-то была даже история от кого-то из Microsoft о том, как они убирали кусок 100% неиспользуемого кода и продукт (вроде офис) валился. Разкоменчивали — работал. Как оказалось «мусор» брался именно с того куска, который не использовался, и на результате этого мусора была накручен используемый функционал.
Так что детерминированный «мусор» гораздо опасней случайного.
В исходном коде лучше бы написали:
printf(b==0?"zero":"non-zero");
или типа того
+1
у меня была похожая ситуация, косяк был не в некорректной инициализации, а в том что я рано память высвобождал, а линки на неё были.
в Debug-сборке работало, а в Release валилось на ура, и я никак не мог догнать почему.
Логгирование памяти тогда помогло.
в Debug-сборке работало, а в Release валилось на ура, и я никак не мог догнать почему.
Логгирование памяти тогда помогло.
0
Результат всегда не определен, т.к. локальная переменная не была инициализирована. Более того, в дебаге и в релизе результат может быть разный. В общем, автор статьи просто С++ изучал по ускоренной методике и не знал о существовании старых давно изученных граблей ;)
+2
Переменную не инициализировали, а на стеке, где она была размещена был мусор.
+1
>Даже предупреждения не дождётесь — подумаешь, объявление неиспользуемой функции!
И это в том месте, где её быть не может! Между прочим, компилятор о большинстве таких грабель предупреждает.
И это в том месте, где её быть не может! Между прочим, компилятор о большинстве таких грабель предупреждает.
+1
Почему значение стековой (auto) переменной как правило будет детерминировано даже на системах без обнуления свободной памяти?
Глупый вопрос.
Перед выполнением main()'a исполняется код crt, который может оставлять на стеке что угодно.
В одной версии crt — на стеке по этому адресу лежит константа, в другой — переменная, которая содержит, например, версию ОСи, и т.д.
Может ли какая-нибудь правильная реализация на системах с обнулением памяти при каждом запуске выдавать разные значения?
легко, смотрите предыдущий ответ :)
даже если не используем crt, то предварительно выполняется системный код, например для WinNT одна из функций это LdrpInitializeProcess().
0
Хм… На Маке еще интереснее результат (copy/paste с самого верхнего примера):
$ ./test
32767
$ gcc -v
Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5666.3~123/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)
$ ./test
32767
$ gcc -v
Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5666.3~123/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)
0
Простите за дурацкий вопрос, но почему
а не
Это могло бы убрать изрядную долю двусмысленности кода, по крайней мере объявлением неиспользуемой функции тут явно не пахнет
std::string a("my string");
а не
std::string a = "my string";
Это могло бы убрать изрядную долю двусмысленности кода, по крайней мере объявлением неиспользуемой функции тут явно не пахнет
+4
И заодно зающать конструктор копирования, когда это не надо! explicit нужно ставить в определение конструктора, тогда неоднозначностей будет меньше!
-4
А почему Вы решили, что будет использован конструктор копирования? Компилятор не глупый :)
+3
Шилдт говорит, что в случае
myobj a = 123;
используется обычный конструктор с одним параметром соответствующего типа, так что конструктор копирования лишний раз вызываться не будет.+2
В обоих случаях будет вызыван один и тот же конструктор std::string(const char*)
Можно предположить, что будет operator= (но его не будет — присваивать можно только к существующему объекту, инициализация — не присваивание и делается конструктором), но без копирующего конструктора в первом случае как обойтись?
Можно предположить, что будет operator= (но его не будет — присваивать можно только к существующему объекту, инициализация — не присваивание и делается конструктором), но без копирующего конструктора в первом случае как обойтись?
+1
100% нет тут конструктора копирования, это просто другая форма записи.
+1
Какая разница какой конструктор будет вызван, когда они делают одно и тоже? В чем провинился copy ctor?
Ну и не надо explicit как мантру повторять, он нужен только там где он нужен и не более того. Есть много мест, где неявное преобразование является желаемым поведением.
Ну и не надо explicit как мантру повторять, он нужен только там где он нужен и не более того. Есть много мест, где неявное преобразование является желаемым поведением.
0
Да, конечно же конструктор в string не объявлен как explicit, и сам я всегда пишу равно. Но тогда бы и задачки не было. А скобочки по ошибке добавляют часто. Тем более, что:
MyClass* c1 = new MyClass(); // всё супер!
MyClass с2(); // а вот тут мы попали
Благо, в этом случае при использовании с2 будет ошибка-1
А зачем там вообще скобки во втором случае? Это какая-то нотация или привычка? У меня скобки ассоциируются с функциями, ну или в крайнем случае с приведением типов, но зачем ставить скобки, особенно пустые, около имени переменной?..
+1
в конструкторах так не пишете —
class A
{
private:
int a, b;
public:
A(int a, int b) : _a(a), _b(b)
{
}
}
+2
Я пишу так:
class A
{
private:
int a, b;
public:
A(int _a, int _b)
{
a = _a;
b = _b;
}
}
-5
И тратите лишние такты) Списки инициализации не просто так придумали.
-1
Но так не инициализировать константы.
0
Вообще-то, запись
прекрасно работает. А использование идентификаторов с подчеркиванием в начале — запрещается Стандартом, так как такие идентификаторы зарезервированы для разработчиков языка/компилятора/стандартных библиотек.
class A
{
private:
int a, b;
public:
A(int a, int b) : a(a), b(b)
{
}
}
прекрасно работает. А использование идентификаторов с подчеркиванием в начале — запрещается Стандартом, так как такие идентификаторы зарезервированы для разработчиков языка/компилятора/стандартных библиотек.
0
Ога а подчеркивание в конце не так удобно визуально, поэтому лучше уж m_a писать.
0
вы не совсем правы
17.4.3.2.1 Global names [lib.global.names]
Certain sets of names and function signatures are always reserved to the implementation:
то есть _a вполне корректно внутри класса, но только не в global namespace'e
а вот _A уже нельзя юзать.
17.4.3.2.1 Global names [lib.global.names]
Certain sets of names and function signatures are always reserved to the implementation:
- Each name that contains a double underscore (_ _) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use.
- Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
то есть _a вполне корректно внутри класса, но только не в global namespace'e
а вот _A уже нельзя юзать.
+5
Да, кстати, а что такое "_a" в вашем примере?
+1
Красивыми граблями устлана дорога в C++
+5
я бы предпочел, обойтись без этих «красивостей».
Иногда пятеро в монитор смотрят и балдеют, что же это такое, и почему, а как… хмммм… бывает весело но потом.
Иногда пятеро в монитор смотрят и балдеют, что же это такое, и почему, а как… хмммм… бывает весело но потом.
+1
Да, увы. Вот и статья зи цикла: повеселиться. Вообще, задачка про a(b) показывалась куче народу на протяжении многих лет. Статистика печальная — без нулевой подсказки правильный ответ что такое a(b) дали единицы.
0
По мне так вполне очевидная вещь.
Может потому что я читал стандарт Си и писал свой компилятор :)
Может потому что я читал стандарт Си и писал свой компилятор :)
-1
> Уже натерпевшиеся от своего любимого языка, но ещё не прошерстившие всех бизонов gcc, почувствуют подвох — и правильно
Без подвохаи те, кто писал синтаксический анализатор С/C++ и знают, что a(b) многим чем может быть. На С всё просто — там сканер заглядывает в таблицу символов. В С++ ситуация сложнее из-за скопов и шаблонов. Из-за последних пришлось придумывать typename, чтобы в теле шаблонизированной функции подсказывать что является типом.
Без подвохаи те, кто писал синтаксический анализатор С/C++ и знают, что a(b) многим чем может быть. На С всё просто — там сканер заглядывает в таблицу символов. В С++ ситуация сложнее из-за скопов и шаблонов. Из-за последних пришлось придумывать typename, чтобы в теле шаблонизированной функции подсказывать что является типом.
0
Странный сумбур: вы с одном проблемы перескакиваете на другую) По теме, каждый уважающий себя С++ программист прочел всего Саттера и Майерса и на подобном его уже не словишь ;)
0
О сколько нам открытий чудных
Готовят просвещенья дух…
мб хватит постов в стиле «смотрите как оказывается оно поступает»?
Готовят просвещенья дух…
мб хватит постов в стиле «смотрите как оказывается оно поступает»?
+2
И стилистика и суть поста — отвратительна. Автор, со своими «подсказочками», «мусипусичками» и прочей ерундой идите преподавать в детский сад.
0
И стилистика и изложение решений с многократными подсказочками сильно напоминает эту книгу
www.ozon.ru/context/detail/id/1908029/
сейчас под рукой нет, чтобы проверить
www.ozon.ru/context/detail/id/1908029/
сейчас под рукой нет, чтобы проверить
0
Хорошо, что вспомнили и эту книжку. Были ещё Майерс, Саттер, а в статье упоминается Александреску. Но только данная статья полностью моя — основная задачка ниоткуда не содрана, но ближе всего будут тексты стандарта, глава 7. И особенно оттуда — Ambiguity resolution.
+1
Ну и отвратительный же у вас стиль написания. Имейте хоть каплю уважения к читателям.
+1
Уважаемый рецензент, разве я кому-то грубил? кому-то демонстрировал своё неуважение?
0
Да нет, никому не грубили. Просто перечитайте еще раз. Такое количество не литературных оборотов, каких-то присказок и просторечий просто невозможно. Из-за этого докопаться до смысла статьи очень трудно.
+1
Извиняйте, если не понравился стиль. Я в тексте и у Шишкова присил прощения, намекая на текст, наверняка вам известный. Ещё, Александра Сергеевича уже цитировал один из рецензентов. Времена, конечно, изменились, и всё-таки разрешите припомнить нашего великого поэта ещё раз в контексте моего повествования:
А вижу, я винюсь пред вами,
Что уж и так мой бедный слог
Пестреть гораздо б меньше мог
Иноплеменными словами.
А вижу, я винюсь пред вами,
Что уж и так мой бедный слог
Пестреть гораздо б меньше мог
Иноплеменными словами.
0
Не получается у меня 0 и -1 под FreeBSD:
%gcc -O0 test.c -o test
%./test
24
%gcc -O1 test.c -o test
%./test
-1
%gcc -O2 test.c -o test
%./test
-1
%gcc -O3 test.c -o test
%./test
-1
%gcc -O0 test.c -o test
%./test
24
%gcc -O1 test.c -o test
%./test
-1
%gcc -O2 test.c -o test
%./test
-1
%gcc -O3 test.c -o test
%./test
-1
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Уж такой элементарный C/С++: может->является