C++ — У меня ошибка


Содержание

У меня есть ошибка при запуске кода в блоке кода, я использую c и c++

У меня проблема с моим кодом C++.

2 cpp файлов (main.cpp, function.СРР)
2 файла заголовка (1 для описания программы, 1 для библиотек и прототипов функций)

Эти четыре файла находятся в одной папке с простым именем. В этой папке также есть файл проекта.

Я сделал проект из версии Codebl 12 12.11, стер default main.cpp в проекте.

И из панели проекта, которая находится в верхней части блока кода, я добавил два файла cpp выше, но не два файла заголовка. Это была инструкция моего профессора.

Я включил два файла заголовка в основной.cpp и включил один файл заголовка (который имеет библиотеки) в функцию.СРР.

Когда я управлял им, он строился и работал нормально. Однако, когда я отправил свой проект моему профессору, он не мог запустить проект. Он сказал, что код существует немедленно, и ничего не происходит.

В моем codebl.из Windows, программы компилятора IDE, где я сделал свой проект, я не мог найти ошибку.
Однако, когда я попробовал тот же проект с моего mac(у меня есть 2 компьютера), используя codeblblock, нет ошибки, но предупреждение появляется так.

warning: LD: warning: игнорирование файла obj / Debug / function.o, файл был создан для неподдерживаемого формата файла (0x4c 0x 1 0x c 0x 0 0x 0 0x 0 0 0x 0 0 0x 0 0x ….0 0x 0) которая не является связанной архитектурой (x86_64): obj/Debug/function.oignoring file obj.

= = = Ошибка сборки: 0 ошибка(ошибки). 1 предупреждение(S) (0 минут(S), 0 отправить (s)) ==

Я не знаю, где починить.

Это мое главное.СРР.

и это функция.СРР

имя файла-описания-Project_Description.ч
он не добавляется в проект, а находится в одной папке с проектом и двумя cpp-файлами.
он начинается как

в комментарии есть описания программы.
и ничто не находится вне комментария.

Существует другой файл заголовка, который имеет прототипы, библиотеки в нем.

Это и есть конец.

Может ли кто-нибудь помочь мне найти ошибку и исправить ее?

У меня ошибка, как исправить c++? [закрыт]

error C2679: бинарный «>>»: не найден оператор, принимающий правый операнд типа «std::string» (или приемлемое преобразование отсутствует)

Закрыт по причине того, что непонятна суть вопроса участниками Abyx, Pavel Mayorov, Kyubey, Nicolas Chabanovsky ♦ 5 май ’15 в 14:02 .

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

Ошибка Microsoft Visual C++ Runtime Library и её исправление

Описание ошибки

Некоторые пользователи в процессе работы с какими-то программами или играми могут столкнуться со следующей ошибкой:

Microsoft Visual C++ Runtime Library
Runtime error!

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

Отсутствие в системе нужных файлов Microsoft Visual C++

Одной из распространенных причин по появлению подобной ошибки может стать отсутствие нужных библиотек от Microsoft Visual C++. Для того, чтобы их установить, нужно скачать специальный набор этих библиотек, которые именуются как «Распространяемый пакет Microsoft Visual C++».

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

Установка Microsoft .NET Framework

Кроме библиотек Microsoft Visual C++ программа может нуждаться в определенной версии Microsoft .NET Framework. Не лишним будет скачать и установить хотя бы версии .NET Framework 3.5 и 4:

Обновление версии DirectX

Так же не лишним будет обновить версию DirectX до последней. Если у вас Windows XP, и вы установили некий «DirectX 10 для Windows XP» — немедленно удалите. Скачать последнюю версию Microsoft DirectX можно по этой ссылке .

Поврежденные файлы программы

Еще часто может быть, что поврежденны файлы самой программы или игры, поэтому не лишним будет попробовать переустановить её. Что касается игр, то многие сервисы цифровой дистрибюции (Steam и другие) имеют функцию проверки файлов игры на повреждения.

Проверка компьютера на вирусы

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

Урок №7. Решения самых распространенных проблем

Обновл. 21 Фев 2020 |

В этом уроке мы рассмотрим наиболее частые проблемы, с которыми сталкиваются новички в C++.

Проблема №1

Как использовать русский язык в программах C++?

Ответ №1

Чтобы выводить кириллицу в C++ нужно подключить заголовочный файл Windows.h:

И прописать следующие две строчки в функции main():

Проблема №2

При выполнении программы появляется чёрное консольное окно, а затем сразу пропадает.

Ответ №2

Некоторые компиляторы (например, Bloodshed’s Dev C++) автоматически не задерживают консольное окно после того, как программа завершила своё выполнение. Если проблема в компиляторе, то следующие два шага решат эту проблему:

Во-первых, добавьте следующую строчку кода в верхнюю часть вашей программы:

Во-вторых, добавьте следующий код в конец функции main() (прямо перед оператором return):

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

Другие решения, такие как system(«pause»); , могут работать только на определённых операционных системах, поэтому вариант выше предпочтительнее.

Примечание: Visual Studio не задерживает консольное окно, если выполнение запущено с отладкой («Отладка» > «Начать отладку» или F5). Если вы хотите, чтобы была пауза — воспользуйтесь решением выше или запустите программу без отладки («Отладка» > «Запуск без отладки» или Ctrl+F5).

Проблема №3

При компиляции программы я получаю следующую ошибку:
«c:vcprojectstest.cpp(263) :fatal error C1010: unexpected end of file while looking for precompiled header directive».

Ответ №3

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

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

Проблема №4

При использовании cin, cout или endl компилятор говорит, что cin, cout или endl являются «undeclared identifier» (необъявленными идентификаторами).

Ответ №4

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

Во-вторых, убедитесь, что cin, cout или endl имеют префикс “std::”. Например:

Проблема №5

При использовании endl для перехода на новую строку, появляется ошибка, что end1 является «undeclared identifier».

Ответ №5

Убедитесь, что вы не спутали букву l (нижний регистр L) в endl с цифрой 1. В endl все символы являются буквами. Также легко можно спутать заглавную букву О с цифрой 0 (нуль).

Проблема №6

Моя программа компилируется, но работает не так как нужно. Что мне делать?

Ответ №6

Проблема №7

Как включить нумерацию строк в Visual Studio?

Ответ №7


Перейдите в меню «Средства» > «Параметры»:

Затем откройте вкладку «Текстовый редактор» > «Все языки» > «Общие» и поставьте галочку возле «Номера строк», затем нажмите «ОК»:

Проблема №8

При компиляции программы я получаю следующую ошибку: «unresolved external symbol _main or _WinMain@16».

Ответ №8

Это означает, что ваш компилятор не может найти главную функцию main(). Все программы должны содержать эту функцию.

Здесь есть несколько пунктов, которые нужно проверить:

Есть ли в вашей программе функция main()?

Слово main написано правильно?

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

Подключен ли файл, содержащий функцию main(), к компиляции?

Проблема №9

При компиляции программы я получаю следующее предупреждение: “Cannot find or open the PDB file”.

Ответ №9

Это не ошибка, а предупреждение. На работоспособность вашей программы оно не повлияет. Тем не менее, в Visual Studio вы можете решить всё следующим образом: перейдите в меню «Отладка» > «Параметры» > «Отладка» > «Символы» и поставьте галочку возле «Серверы символов (Майкрософт)», затем нажмите «ОК».

Проблема №10

Я использую Code::Blocks или G++, но функционал C++11/C++14 не работает.

Ответ №10

В Code::Blocks перейдите в «Project» > «Build options» > «Compiler settings» > «Compiler flags» и поставьте галочку возле пункта «Have g++ follow C++14 ISO C++ language standard». Смотрите урок № 4 — там есть скриншоты, как это сделать.

При компиляции в g++, добавьте следующий код в командную строку:

Проблема №11

Я запустил программу, появилось консольное окно, но ничего не выводится.

Ответ №11

Ваш антивирус может блокировать выполнение вашей программы. Попробуйте отключить его на время и запустите программу ещё раз.

У меня есть другая проблема, с которой я не могу разобраться. Как и где я могу получить ответ?

По мере прохождения уроков, у вас, несомненно, появятся вопросы или вы столкнетесь с проблемами. Что делать?

Цукерберг рекомендует:  Аndroid-приложение с онлайн-подкачкой данных из базы MySQL через скрипты PHP

Во-первых, спросите у Google. Четко сформулируйте вашу проблему и просто погуглите. Если у вас есть сообщение об ошибке — скопируйте его и вставьте в поиск Google, используя кавычки. Скорее всего, кто-то уже задал такой же вопрос, как у вас, и получил на него ответ.

Если Google не помог, то спросите на специализированных сервисах вопросов/ответов/форумов. Вот самые популярные из них:

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

Ошибка Microsoft Visual C++ Runtime Library. Как исправить?

Не так давно помогал одному хорошему знакомому с настройкой компьютера: у него при запуске любой игры выскакивала ошибка Microsoft Visual C++ Runtime Library… Так собственно и родилась тема этого поста: опишу в нем подробные шаги по восстановлению работоспособности ОС Windows и избавлению от этой ошибки.

Вообще, ошибка Microsoft Visual C++ Runtime Library может появиться по многим причинам и разобраться, порой, не так просто и быстро.

Типичный пример ошибки Microsoft Visual C++ Runtime Library.

1) Установка, обновление Microsoft Visual C++

Многие игры и программы были написаны в среде Microsoft Visual C++. Естественно, если у вас нет этого пакета, то игры работать не будут. Чтобы это исправить, нужно установить пакет Microsoft Visual C++ (кстати, распространяется бесплатно).

Ссылки на офиц. сайт Microsoft:

2) Проверка игры/приложения

Вторым шагом по устранению ошибок запуска приложений и игр — станет проверка и переустановка самих этих приложений. Дело в том, что возможно у вас были испорчены какие-нибудь системные файлы игры (dll, exe файлы). Причем, испортить могли как вы сами (случайно), так и например, «зловредные» программы: вирусы, трояны, рекламное ПО и пр. Часто банальная переустановка игры полностью избавляла от всех ошибок.

3) Проверка компьютера на вирусы

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

Рекомендую проверить компьютер несколькими антивирусами, кроме этого ознакомиться с этими материалами:

4) NET Framework

NET Framework — программная платформа, на которой разрабатывают различные программы и приложения. Чтобы эти приложения могли запуститься, у вас на компьютере должна быть установлена требуемая версия NET Framework.

Все версии NET Framework + описание.

5) DirectX

Самая распространенная (по моим личным подсчетам) из-за чего происходит ошибка Runtime Library — это «самопальные» установки DirectX. Например, многие устанавливают на Windows XP 10-ю версию DirectX (в рунете на многих сайтах есть такая версия). Но официально XP не поддерживает 10-ю версию. В результате начинают сыпаться ошибки…

Рекомендую удалить через диспетчер задач (Пуск/панель управления/установка и удаления программ) DirectX 10, а затем произвести обновление DirectX через рекомендованный установщик от Microsoft (более подробно о вопросах с DirectX — см. в этой статье).

6) Драйвера на видеокарту

Обязательно проверьте драйвера на видеокарту, даже если до этого ошибок не наблюдалось.

1) Рекомендую проверить официальный сайт вашего производителя и скачать последнюю версию драйвера.

2) Затем удалить полностью старые драйвера из ОС, и установить новые.

3) Попробовать снова запустить «проблемную» игру/приложение.

PS

1) Некоторые пользователи заметили одну «незакономерную закономерность» — если у вас время и дата в компьютере не правильные (передвинуты сильно на будущее), то ошибка Microsoft Visual C++ Runtime Library может появляться и из-за этого. Дело в том, что разработчики программ ограничивают их срок использования, и, естественно, программы проверяя дату (видя что наступил крайний срок «X») — прекращают свою работу…

Исправить очень просто: установить реальную дату и время.

Обработка ошибок: Защитное программирование

Введение

В любой программе, сложнее чем «Hello, world» , неизбежно будут происходить ошибки и различные сбои. Поэтому если вы хотите писать надежный и стабильный код, то обязаны заботиться обо всем этом. Конечно, в большинстве случаев нет смысла становиться параноиком и проверять абсолютно все. С другой стороны, во многом это зависит от области применения приложения, которое вы разрабатываете. Если это система контроля банковских переводов или управления полетом спутника, то единственная ошибка в коде может обойтись очень дорого. В этом случае вам на помощь приходит «защитное программирование». Одно из лучших описаний этой методики, на мой взгляд, приводится в следующих книгах:

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

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

Реклама

Коды ошибок

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

Двойная ответственность

Вот как может выглядеть подобная функция:

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

Такой способ применяется довольно часто, но он имеет некоторые очевидные недостатки. Например, когда мы инициализируем переменную userID значением, которое возвращает функция registerUser() , то на самом деле мы врем. Ведь эта переменная хранит идентификатор пользователя ИЛИ код ошибки, то есть должна называться userIDOrErrorCode . Имя получилось длинным и пользоваться им будет неудобно. Но сразу становится понятно, что эта переменная имеет два назначения (выглядит подозрительно, не правда ли?). Однако даже это не является главным недостатком. В какой-то момент требования к типу идентификатора могут измениться. Например, мы можем решить, что лучше использовать беззнаковое целое число:

Обратите внимание, что в первую очередь я добавил определение typedef для типа UserID . Теперь мы сможем менять фактический тип идентификатора всего в одной строке. Для сравнения, когда мы явно пользовались типом int , то в зависимости от объема кода подобная тривиальная операция могла бы занять несколько часов. Поэтому старайтесь не повторяться (см. Принцип DRY в действии).

Кроме того, теперь мы явно указываем, что функция registerUser() возвращает именно идентификатор UserID , а не идентификатор ИЛИ код ошибки. Иначе мы вновь обманываем тех, кто будет вызывать нашу функцию.

Указатель для ошибки

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

Этой функцией мы можем пользоваться следующим образом:

Выглядит неплохо. Но у вас мог возникнуть вопрос: «А какое значение будет у переменной userID , если ok == false «? Можно предположить, что это будет 0 , то есть функция registerUser() должна вернуть некое нейтральное значение. Например, в случае, когда ожидается возврат класса или структуры, это может быть Null -объект или объект с функцией-членом на подобии isValid() , которая возвращает false , если экземпляр класса находится в некорректном состоянии. Кстати, если бы registerUser() была не обычной функцией, а являлась членом класса, то мы бы могли вообще не возвращать никаких признаков ошибки, но добавить в сам класс что-то вроде getLastError() .

Вот это поворот

Рассмотренный подход вполне справляется со своими задачами, но обычно для подобных функций в стиле C используют другую сигнатуру. Она выглядит следующим образом:

Мы поменяли местами идентификатор и переменную с информацией об успешности выполнения регистрации. Пользоваться этой функцией можно следующим образом:


Однако, как вы можете видеть, принципиально ничего не изменилось. Нам все равно приходится инициализировать идентификатор userID значением по умолчанию, но теперь это происходит не в самой функции, а до ее вызова. Если мы не хотим, чтобы переменная userID имела смысл без явной инициализации (хотя всегда есть возможность добавить в иерархию классов Null -объект), то можно воспользоваться альтернативным решением:

На этот раз registerUser() принимает не просто указатель на UserID , а двойной указатель. То есть память для идентификатора пользователя выделяется внутри функции registerUser() . А чтобы быть последовательными, освобождать память для userID мы будем не оператором delete , а с помощью функции releaseMemory() , которую сами должны предусмотреть.

Подобным образом часто пишутся C-библиотеки, которые представляют собой обертку над ООП-кодом на C++. Это делается для получения высокой совместимости библиотек, что особенно актуально для Windows. Вы не можете подключить библиотеку на C++ к проекту, если версии компиляторов, с которой работаете вы, и с которой была собрана библиотека, отличаются. Поэтому если вы хотите сохранить реализацию своей библиотеки закрытой, то оказываетесь ограничены использованием низкоуровневых типов данных, которые есть в C. Но чтобы не отбрасывать свои наработки и не переписывать весь код заново на чистом C, используется показанная выше методика. При этом в пользовательском коде вся работа ведется не с самими экземплярами классов, а с указателями на них. А для выделения и освобождения памяти используются специально предусмотренные функции, которые предоставляет библиотека. Более того, определений классов в заголовочных файлах библиотеки нет вовсе (для простоты я сделал допущение, что мы можем создать экземпляр класса User , хотя его тоже не было бы). Вам доступно лишь объявление, которого достаточно для определения указателя на класс. Из-за этого все вызовы функций-членов должны осуществляться также с помощью C-функций, которые ожидают получить указатель на объект, а входные и выходные аргументы должны быть представлены с помощью примитивных типов, на подобии int или char . Впрочем, это было небольшое отступление от нашей темы. Однако если у вас есть желание узнать об этом вопросе поподробнее, то пишите свои пожелания в комментариях и я подготовлю соответствующую полноценную заметку.

Цукерберг рекомендует:  Списки голосования с использованием PHP

Кто там?

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

Чтобы избежать проблем с областью видимости при объявлении перечисления ResultCode , мы создали пространство имен RegistrationLib . Использование namespace -ов вообще является хорошей практикой при написании кода, который вы планируете кому-то передавать. Теперь registerUser() не просто говорит о том, что что-то случилось, но и указывает причину. Конечно, в качестве примера я взял простейший набор возможных типов ошибок, которые могли бы случиться. К тому же, они не так детальны, как хотелось бы. Проблем с заполнением структуры User может быть немало, а уж при работе с базами еще больше. Однако я думаю, что суть вы уловили.

Чуть выше

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

Допустим, мы хотим реализовать высокоуровневую функцию, в которой сначала получаем данные пользователя, затем пробуем провести его регистрацию (с помощью нашей функции registerUser() ), а в конце отправляем идентификатор нового пользователя на удаленный сервер, если регистрация удалась. Сначала рассмотрим самый линейный вариант:

Я думаю, у вас не вызовет трудностей разобраться с представленным кодом. В целом он основывается на тех принципах, которые мы уже обсудили выше. Но логика работы функции onUserDataReady() выглядит довольно запутанной. Таковой она и является. Это связано с тем, что мы использовали множество вложенных условных конструкций, что осложняет чтение кода. Несколько улучшить ситуацию нам поможет следующий прием:

Получившийся код выглядит несколько проще. Это достигается за счет уменьшения вложенности проверок. Однако обратите внимание, что перед вызовом registerUser() и sendUserIDToRemoteServer() нам приходится проверять результат выполнения предыдущих действий. Такая необходимость появляется по той причине, что если на n -ом шаге что-то случилось, то все оставшиеся шаги уже не имеют смысла. Фактически после ошибки на каком-то из шагов функция onUserDataReady() должна завершаться. Для этого мы бы могли попробовать сделать что-то подобное:

Конечно, код стал еще легче, но теперь мы имеем утечку памяти, ведь возврат из функции при завершении обработки ошибок происходит раньше вызова releaseMemory() . В этом случае у нас есть несколько вариантов. Первый из них заключается в том, чтобы перед каждым return вставить вызов releaseMemory() . Но так мы получим крайне неудачную конструкцию с дублированием кода. Поэтому такой способ сразу отбрасываем. Другой подход многие бы не одобрили, но он вполне того стоит в нашей ситуации. Его суть заключается в использовании goto :

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

Однако есть еще более надежный и качественный вариант. Он заключается в использовании принципа RAII. Наиболее известным примером реализации этого механизма является Умный указатель. Более подробно об этой идиоме я расскажу во второй части, а сейчас посмотрим, как будет выглядеть код функции onUserDataReady() на основе RAII в нашем случае:

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

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

Реклама

Заключение

Наше знакомство с базовыми принципами обработки ошибок закончено. Мы успели рассмотреть основные способы возврата кодов ошибок; коротко вспомнили принцип создания C-оберток над ООП кодом C++ для создания переносимых библиотек; а также разобрались с возможными вариантами реализации функции-обработчика, которая должна проверять коды ошибок. Встретимся во второй части.

C++ — У меня ошибка

Вас неправильно направили, этот форум для разрабочтиков ПО.

Судя по всему у вас проблема с процессом Igfxsrvc.exe. Обычно это ПО от Интел которое управляет встроенной графикой, но более вероятно что это вирус который прикидывается ПО от Интел. Дальше вам надо удалить это ПО и оно перестанет падать.

Да, в этот форум писать больше не надо. Microsoft.community было правильным местом. Напишите что вы не разработчик, а просто подхаватили какой то зловред.

This posting is provided «AS IS» with no warranties, and confers no rights.

Исключения в С++

Иногда, во время работы программ, встречаются ситуации которые препятствуют дальнейшей нормальной их работе. К примеру при делении числа на ноль, программа завершит работу не смотря на то, сколько пользователь работал в программе, и какой объем данных внес. Программа просто закроется.

И представьте, если до этого пользователь вносил в программу данные несколько часов и проводил расчеты. При таком аварийном закрытии программы все эти данные и расчеты пропадут. Согласитесь – не очень приятно. Также может встретиться такая ситуация, когда программа пытается открыть недоступный в этот момент файл, или запросить больше, чем доступно памяти.

Такого рода ситуации программистам надо стараться предвидеть и строить программы так, чтобы они могли гибко реагировать, а не аварийно закрываться. В моей любимой книге Язык программирования C++. Лекции и упражнения автора С. Прата, дано следующее определение исключениям в С++:

Чтобы вам не сложно было понять механизм работы исключений в С++, рассмотрим их на простом примере. В нем мы предвидим тот случай, что в какой-то момент в ходе расчетов программы, может встретиться деление числа на 0. Наберите и скомпилируйте код, расположенный ниже. Чтобы убедиться в том, как реагирует программа на такую ситуацию, внесите число 0 в переменную num2 (она выступает делителем в примере).

Программирование в C++. Не могу найти ошибку в коде.

Вот код:
#include
#include «rus8.h»
#include
using namespace std;

int main()
<
rus();
double a, b, c;//a, b, c — коэффиценты уравнения
double x0, x1, x2, x3, x4, x5;// х1, х2 — корни уравнения
double D;//D-дискриминант
FILE *f_in;
FILE *f_out;
int retcode;
f_in = fopen(«Input.txt», «r»);
if (f_in == NULL)
<
printf(«Ошибка открытия файла Input.txt. \n»);
return 1;
>
retcode = fscanf (f_in, » a=%lg b=%lg c=%lg», &a, &b, &c);
if (retcode !=3)
<
printf («Ошибка чтения данных из файла Input.txt. \n»
«Проверьте корректность данных. \n»);
return 2;
>
retcode = fclose(f_in);
if (retcode == EOF)
<
printf («Ошибка закрытия файла Input.txt. \n»);
return 3;
>
printf(«Вы получии уравнение: %lgx^2%+lgx%+lg=0\n», a, b, c);
f_out = fopen(«Output.txt», «w»);
if (f_out == NULL)
<
printf(«Ошибка открытия файла Output.txt. \n»);
return 4;
>
if ( a==0 )
<

if (b==0)
<
printf («Ошибка!! !Неверное математическое выражение: %lg=0\n», c);
>
x0=(-c)/b;//нахождение корня при а=0
retcode = fprintf (f_out, «%lg — единственный корень\n», x0);
if (retcode !=2)
<
printf («Ошибка записи данных в файл Output.txt. \n»);
return 5;
return 0;
>
return 0;

>
if (a!=0)
<
D = (b)*(b)-4*a*c;//формула нахождения дискриминанта
if (D 0)
<
x4=((-b)+sqrt(D))/(2*a);//формулы нахождения корней
x5=((-b)-sqrt(D))/(2*a);//квадратного уравнения
retcode = fprintf (f_out, «Первый корень%lg\nВторой корень %lg», x4, x5);
if (retcode !=2)
<
printf («Ошибка записи данных в файл Output.txt. \n»);
return 8;
return 0;
>
>
printf(«Уравнение решено. Ответ находится в файле Output.txt\n»);
>
Вот что он выводит:
1>d:\projects\pract2\pract2\main.cpp(15) : warning C4996: ‘fopen’: This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> d:\mvs08\vc\include\stdio.h(237) : see declaration of ‘fopen’
1>d:\projects\pract2\pract2\main.cpp(21) : warning C4996: ‘fscanf’: This function or variable may be unsafe. Consider using fscanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> d:\mvs08\vc\include\stdio.h(256) : see declaration of ‘fscanf’
1>d:\projects\pract2\pract2\main.cpp(35) : warning C4996: ‘fopen’: This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> d:\mvs08\vc\include\stdio.h(237) : see declaration of ‘fopen’
1>d:\projects\pract2\pract2\main.cpp(66) : warning C4553: ‘==’ : operator has no effect; d >1>d:\projects\pract2\pract2\main.cpp(100) : fatal error C1075: end of file found before the left brace ‘<' at 'd:\projects\pract2\pract2\main.cpp(7)' was matched
1>Build log was saved at «file://d:\projects\pract2\pract2\Debug\BuildLog.htm»
1>pract2 — 1 error(s), 4 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Еще поставил двойное равно == вместо =
x2==-b-sqrt(-D)*i;

А тут пахнет быдлокодом.
return 8;
return 0;

Обработка ошибок: Защитное программирование

Введение

В любой программе, сложнее чем «Hello, world» , неизбежно будут происходить ошибки и различные сбои. Поэтому если вы хотите писать надежный и стабильный код, то обязаны заботиться обо всем этом. Конечно, в большинстве случаев нет смысла становиться параноиком и проверять абсолютно все. С другой стороны, во многом это зависит от области применения приложения, которое вы разрабатываете. Если это система контроля банковских переводов или управления полетом спутника, то единственная ошибка в коде может обойтись очень дорого. В этом случае вам на помощь приходит «защитное программирование». Одно из лучших описаний этой методики, на мой взгляд, приводится в следующих книгах:

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

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

Цукерберг рекомендует:  Копирование текста в делфи - копирование текста в делфи
Реклама

Коды ошибок

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

Двойная ответственность

Вот как может выглядеть подобная функция:

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

Такой способ применяется довольно часто, но он имеет некоторые очевидные недостатки. Например, когда мы инициализируем переменную userID значением, которое возвращает функция registerUser() , то на самом деле мы врем. Ведь эта переменная хранит идентификатор пользователя ИЛИ код ошибки, то есть должна называться userIDOrErrorCode . Имя получилось длинным и пользоваться им будет неудобно. Но сразу становится понятно, что эта переменная имеет два назначения (выглядит подозрительно, не правда ли?). Однако даже это не является главным недостатком. В какой-то момент требования к типу идентификатора могут измениться. Например, мы можем решить, что лучше использовать беззнаковое целое число:

Обратите внимание, что в первую очередь я добавил определение typedef для типа UserID . Теперь мы сможем менять фактический тип идентификатора всего в одной строке. Для сравнения, когда мы явно пользовались типом int , то в зависимости от объема кода подобная тривиальная операция могла бы занять несколько часов. Поэтому старайтесь не повторяться (см. Принцип DRY в действии).

Кроме того, теперь мы явно указываем, что функция registerUser() возвращает именно идентификатор UserID , а не идентификатор ИЛИ код ошибки. Иначе мы вновь обманываем тех, кто будет вызывать нашу функцию.

Указатель для ошибки

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

Этой функцией мы можем пользоваться следующим образом:

Выглядит неплохо. Но у вас мог возникнуть вопрос: «А какое значение будет у переменной userID , если ok == false «? Можно предположить, что это будет 0 , то есть функция registerUser() должна вернуть некое нейтральное значение. Например, в случае, когда ожидается возврат класса или структуры, это может быть Null -объект или объект с функцией-членом на подобии isValid() , которая возвращает false , если экземпляр класса находится в некорректном состоянии. Кстати, если бы registerUser() была не обычной функцией, а являлась членом класса, то мы бы могли вообще не возвращать никаких признаков ошибки, но добавить в сам класс что-то вроде getLastError() .

Вот это поворот

Рассмотренный подход вполне справляется со своими задачами, но обычно для подобных функций в стиле C используют другую сигнатуру. Она выглядит следующим образом:

Мы поменяли местами идентификатор и переменную с информацией об успешности выполнения регистрации. Пользоваться этой функцией можно следующим образом:

Однако, как вы можете видеть, принципиально ничего не изменилось. Нам все равно приходится инициализировать идентификатор userID значением по умолчанию, но теперь это происходит не в самой функции, а до ее вызова. Если мы не хотим, чтобы переменная userID имела смысл без явной инициализации (хотя всегда есть возможность добавить в иерархию классов Null -объект), то можно воспользоваться альтернативным решением:

На этот раз registerUser() принимает не просто указатель на UserID , а двойной указатель. То есть память для идентификатора пользователя выделяется внутри функции registerUser() . А чтобы быть последовательными, освобождать память для userID мы будем не оператором delete , а с помощью функции releaseMemory() , которую сами должны предусмотреть.

Подобным образом часто пишутся C-библиотеки, которые представляют собой обертку над ООП-кодом на C++. Это делается для получения высокой совместимости библиотек, что особенно актуально для Windows. Вы не можете подключить библиотеку на C++ к проекту, если версии компиляторов, с которой работаете вы, и с которой была собрана библиотека, отличаются. Поэтому если вы хотите сохранить реализацию своей библиотеки закрытой, то оказываетесь ограничены использованием низкоуровневых типов данных, которые есть в C. Но чтобы не отбрасывать свои наработки и не переписывать весь код заново на чистом C, используется показанная выше методика. При этом в пользовательском коде вся работа ведется не с самими экземплярами классов, а с указателями на них. А для выделения и освобождения памяти используются специально предусмотренные функции, которые предоставляет библиотека. Более того, определений классов в заголовочных файлах библиотеки нет вовсе (для простоты я сделал допущение, что мы можем создать экземпляр класса User , хотя его тоже не было бы). Вам доступно лишь объявление, которого достаточно для определения указателя на класс. Из-за этого все вызовы функций-членов должны осуществляться также с помощью C-функций, которые ожидают получить указатель на объект, а входные и выходные аргументы должны быть представлены с помощью примитивных типов, на подобии int или char . Впрочем, это было небольшое отступление от нашей темы. Однако если у вас есть желание узнать об этом вопросе поподробнее, то пишите свои пожелания в комментариях и я подготовлю соответствующую полноценную заметку.

Кто там?

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

Чтобы избежать проблем с областью видимости при объявлении перечисления ResultCode , мы создали пространство имен RegistrationLib . Использование namespace -ов вообще является хорошей практикой при написании кода, который вы планируете кому-то передавать. Теперь registerUser() не просто говорит о том, что что-то случилось, но и указывает причину. Конечно, в качестве примера я взял простейший набор возможных типов ошибок, которые могли бы случиться. К тому же, они не так детальны, как хотелось бы. Проблем с заполнением структуры User может быть немало, а уж при работе с базами еще больше. Однако я думаю, что суть вы уловили.

Чуть выше

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

Допустим, мы хотим реализовать высокоуровневую функцию, в которой сначала получаем данные пользователя, затем пробуем провести его регистрацию (с помощью нашей функции registerUser() ), а в конце отправляем идентификатор нового пользователя на удаленный сервер, если регистрация удалась. Сначала рассмотрим самый линейный вариант:

Я думаю, у вас не вызовет трудностей разобраться с представленным кодом. В целом он основывается на тех принципах, которые мы уже обсудили выше. Но логика работы функции onUserDataReady() выглядит довольно запутанной. Таковой она и является. Это связано с тем, что мы использовали множество вложенных условных конструкций, что осложняет чтение кода. Несколько улучшить ситуацию нам поможет следующий прием:

Получившийся код выглядит несколько проще. Это достигается за счет уменьшения вложенности проверок. Однако обратите внимание, что перед вызовом registerUser() и sendUserIDToRemoteServer() нам приходится проверять результат выполнения предыдущих действий. Такая необходимость появляется по той причине, что если на n -ом шаге что-то случилось, то все оставшиеся шаги уже не имеют смысла. Фактически после ошибки на каком-то из шагов функция onUserDataReady() должна завершаться. Для этого мы бы могли попробовать сделать что-то подобное:

Конечно, код стал еще легче, но теперь мы имеем утечку памяти, ведь возврат из функции при завершении обработки ошибок происходит раньше вызова releaseMemory() . В этом случае у нас есть несколько вариантов. Первый из них заключается в том, чтобы перед каждым return вставить вызов releaseMemory() . Но так мы получим крайне неудачную конструкцию с дублированием кода. Поэтому такой способ сразу отбрасываем. Другой подход многие бы не одобрили, но он вполне того стоит в нашей ситуации. Его суть заключается в использовании goto :

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

Однако есть еще более надежный и качественный вариант. Он заключается в использовании принципа RAII. Наиболее известным примером реализации этого механизма является Умный указатель. Более подробно об этой идиоме я расскажу во второй части, а сейчас посмотрим, как будет выглядеть код функции onUserDataReady() на основе RAII в нашем случае:

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

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

Реклама

Заключение

Наше знакомство с базовыми принципами обработки ошибок закончено. Мы успели рассмотреть основные способы возврата кодов ошибок; коротко вспомнили принцип создания C-оберток над ООП кодом C++ для создания переносимых библиотек; а также разобрались с возможными вариантами реализации функции-обработчика, которая должна проверять коды ошибок. Встретимся во второй части.

Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих