Компиляция программы на C ++ выполняется в несколько этапов, как указано в 2.2 (кредиты для Кейта Томпсона для ссылки) :
Превалирование среди правил синтаксиса
- Физические символы исходного файла сопоставляются в соответствии с реализацией в соответствии с базовым набором символов источника (ввод символов новой строки для индикаторов конца строки) при необходимости. [SNIP]
- Каждый экземпляр символа обратной косой черты (\), за которым сразу следует символ новой строки, удаляется, сплайсируя физические исходные строки для формирования логических строк источника. [SNIP]
- Исходный файл разбивается на токены предварительной обработки (2.5) и последовательности символов пробела (включая комментарии). [SNIP]
- Выполнены предпроцессорные директивы, макро-вызовы разворачиваются и выполняются операторные выражения _Pragma. [SNIP]
- Каждый элемент набора символов в символьном литерале или строковый литерал, а также каждая escape-последовательность и универсальное имя-символа в символьном литерале или не- -raw строковый литерал, преобразуется в соответствующий член набора символов выполнения; [SNIP]
- Соединительные маркеры литералов строки объединены.
- Символы пробела, разделяющие токены, уже не являются значимыми. Каждый токен предварительной обработки преобразуется в токен. (2.7). Результирующие маркеры синтаксически и семантически анализируются и переводятся как единица перевода. [SNIP]
- Устанавливаемые единицы перевода и единицы экземпляра объединяются следующим образом: [SNIP]
- Все ссылки на внешние сущности решена. Компоненты библиотеки связаны для удовлетворения внешних ссылок на объекты, не определенные в текущем переводе. Весь такой переводчик выводится в образ программы, который содержит информацию, необходимую для выполнения в среде выполнения. (акцент мой)
[footnote] Реализации должны вести себя так, как если бы эти отдельные фазы происходили, хотя на практике различные фазы могли быть свернуты вместе.
Указанные ошибки возникают на этом последнем этапе компиляции, чаще всего называемом связыванием. Это в основном означает, что вы собрали кучу файлов реализации в объектные файлы или библиотеки, и теперь вы хотите заставить их работать вместе.
Скажите, что вы определили символ
a
вa.cpp
. Теперьb.cpp
объявил этот символ и использовал его. Перед связыванием он просто предполагает, что этот символ был определен где-то , но он пока не заботится о том, где. Фаза связывания отвечает за поиск символа и правильную привязку его кb.cpp
(ну, собственно, к объекту или библиотеке, которая его использует).Если вы используете Microsoft Visual Studio, вы будете см., что проекты генерируют файлы
.lib
. Они содержат таблицу экспортированных символов и таблицу импортированных символов. Импортированные символы разрешены против библиотек, на которые вы ссылаетесь, и экспортированные символы предоставляются для библиотек, которые используют этот.lib
(если есть).Подобные механизмы существуют для других компиляторов / платформ.
Общие сообщения об ошибках:
error LNK2001
,error LNK1120
,error LNK2019
для Microsoft Visual Studio иundefined reference to
symbolName для GCC.Код:
struct X { virtual void foo(); }; struct Y : X { void foo() {} }; struct A { virtual ~A() = 0; }; struct B: A { virtual ~B(){} }; extern int x; void foo(); int main() { x = 0; foo(); Y y; B b; }
генерирует следующие ошибки с GCC:
/home/AbiSfw/ccvvuHoX.o: In function `main': prog.cpp:(.text+0x10): undefined reference to `x' prog.cpp:(.text+0x19): undefined reference to `foo()' prog.cpp:(.text+0x2d): undefined reference to `A::~A()' /home/AbiSfw/ccvvuHoX.o: In function `B::~B()': prog.cpp:(.text._ZN1BD1Ev[B::~B()]+0xb): undefined reference to `A::~A()' /home/AbiSfw/ccvvuHoX.o: In function `B::~B()': prog.cpp:(.text._ZN1BD0Ev[B::~B()]+0x12): undefined reference to `A::~A()' /home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1Y[typeinfo for Y]+0x8): undefined reference to `typeinfo for X' /home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1B[typeinfo for B]+0x8): undefined reference to `typeinfo for A' collect2: ld returned 1 exit status
и аналогичные ошибки с Microsoft Visual Studio:
1>test2.obj : error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ) 1>test2.obj : error LNK2001: unresolved external symbol "int x" (?x@@3HA) 1>test2.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall A::~A(void)" (??1A@@UAE@XZ) 1>test2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall X::foo(void)" (?foo@X@@UAEXXZ) 1>...\test2.exe : fatal error LNK1120: 4 unresolved externals
. Общие причины включают в себя:
- Не удалось связать с соответствующими библиотеками / объектными файлами или скомпилировать файлы реализации
- Объявленная и неопределенная переменная или функция.
- Общие проблемы с элементами класса
- Реализации шаблонов не отображаются.
- Символы были определены в программе на языке C и использовались в коде C ++.
- Неправильно импортировать / экспортировать методы / классы по модулям / dll. (Спецификация MSVS)
- Зависимость круговой библиотеки
- неопределенная ссылка на `WinMain @ 16 '
- Порядок взаимозависимых библиотек
- Несколько исходных файлов с таким же именем
- Мистификация или отсутствие включения расширение .lib при использовании
#pragma
(Microsoft Visual Studio)- Проблемы с друзьями шаблонов
- Несогласован
UNICODE
определения
В случае, если это полезно, еще несколько вариантов для рассмотрения, все сбрасываемые вместе (стоп-файл вместо повторных попыток, спящий режим, продолжение более крупного цикла), возможно, полезно.
bigLoop:
while(!stopFileExists()) {
try {
// do work
break;
}
catch (ExpectedExceptionType e) {
// could sleep in here, too.
// another option would be to "restart" some bigger loop, like
continue bigLoop;
}
// ... more work
}
Обязательное решение «enterpriseisy»:
public abstract class Operation {
abstract public void doIt();
public void handleException(Exception cause) {
//default impl: do nothing, log the exception, etc.
}
}
public class OperationHelper {
public static void doWithRetry(int maxAttempts, Operation operation) {
for (int count = 0; count < maxAttempts; count++) {
try {
operation.doIt();
count = maxAttempts; //don't retry
} catch (Exception e) {
operation.handleException(e);
}
}
}
}
И для вызова:
OperationHelper.doWithRetry(5, new Operation() {
@Override public void doIt() {
//do some stuff
}
@Override public void handleException(Exception cause) {
//recover from the Exception
}
});
Хотя try/catch
в while
хорошо известна и хорошая стратегия, я хочу предложить вам рекурсивный вызов:
void retry(int i, int limit) {
try {
} catch (SomeException e) {
// handle exception
if (i >= limit) {
throw e; // variant: wrap the exception, e.g. throw new RuntimeException(e);
}
retry(i++, limit);
}
}
следующее мое решение с очень простым подходом!
while (true) {
try {
/// Statement what may cause an error;
break;
} catch (Exception e) {
}
}
Как обычно, лучший дизайн зависит от конкретных обстоятельств. Обычно, я пишу что-то вроде:
for (int retries = 0;; retries++) {
try {
return doSomething();
} catch (SomeException e) {
if (retries < 6) {
continue;
} else {
throw e;
}
}
}
Здесь многоразовый и более общий подход для Java 8+, который не требует внешних библиотек:
public interface IUnreliable<T extends Exception>
{
void tryRun ( ) throws T;
}
public static <T extends Exception> void retry (int retryCount, IUnreliable<T> runnable) throws T {
for (int retries = 0;; retries++) {
try {
runnable.tryRun();
return;
} catch (Exception e) {
if (retries < retryCount) {
continue;
} else {
throw e;
}
}
}
}
Использование:
@Test
public void demo() throws IOException {
retry(3, () -> {
new File("/tmp/test.txt").createNewFile();
});
}
Ваш точный сценарий, обработанный через Failsafe :
RetryPolicy retryPolicy = new RetryPolicy()
.retryOn(NearlyUnexpectedException.class);
Failsafe.with(retryPolicy)
.onRetry((r, f) -> fix_the_problem())
.run(() -> some_instruction());
Довольно просто.
Простым способом решения проблемы было бы обернуть try / catch в цикле while и поддерживать подсчет. Таким образом, вы можете предотвратить бесконечный цикл, проверив счетчик против какой-либо другой переменной, сохраняя при этом журнал ваших сбоев. Это не самое изысканное решение, но оно будет работать.
Я не уверен, что это «профессиональный» способ сделать это, и я не совсем уверен, что он работает на все.
boolean gotError = false;
do {
try {
// Code You're Trying
} catch ( FileNotFoundException ex ) {
// Exception
gotError = true;
}
} while ( gotError = true );
Я знаю, что здесь уже много похожих ответов, а у меня мало чем отличается, но я все равно отправлю его, потому что он касается конкретного случая / проблемы.
Когда вы работаете с facebook Graph API
в PHP
вы иногда получаете сообщение об ошибке, но при повторном повторении одного и того же результата вы получите положительный результат (для различных магических причин Интернета, выходящих за рамки этого вопроса). В этом случае нет необходимости исправлять fix любую ошибку, но просто попробуйте еще раз, потому что произошла какая-то «ошибка facebook».
Этот код используется сразу после создания facebook session:
//try more than once because sometimes "facebook error"
$attempt = 3;
while($attempt-- > 0)
{
// To validate the session:
try
{
$facebook_session->validate();
$attempt = 0;
}
catch (Facebook\FacebookRequestException $ex)
{
// Session not valid, Graph API returned an exception with the reason.
if($attempt <= 0){ echo $ex->getMessage(); }
}
catch (\Exception $ex)
{
// Graph API returned info, but it may mismatch the current app or have expired.
if($attempt <= 0){ echo $ex->getMessage(); }
}
}
Кроме того, если число циклов for
обращается в нуль ($attempt--
), это довольно легко изменить количество попыток в будущем.
Вы можете использовать аннотации AOP и Java из jcabi-aspect (я разработчик):
@RetryOnFailure(attempts = 3, delay = 5)
public String load(URL url) {
return url.openConnection().getContent();
}
Вы также можете использовать @Loggable
и @LogException
аннотаций.
Используйте кнопку do-while для создания блока повторной попытки.
boolean successful = false;
int maxTries = 3;
do{
try {
something();
success = true;
} catch(Me ifUCan) {
maxTries--;
}
} while (!successful || maxTries > 0)
Все попытки Try-Catch позволяют вашей программе терпеть неудачу изящно. В выводе catch вы обычно пытаетесь зарегистрировать ошибку и, возможно, откатите изменения, если вам нужно.
bool finished = false;
while(finished == false)
{
try
{
//your code here
finished = true
}
catch(exception ex)
{
log.error("there was an error, ex");
}
}
Большинство этих ответов по существу одинаковы. Моя тоже, но это форма, которую мне нравится
boolean completed = false;
Throwable lastException = null;
for (int tryCount=0; tryCount < config.MAX_SOME_OPERATION_RETRIES; tryCount++)
{
try {
completed = some_operation();
break;
}
catch (UnlikelyException e) {
lastException = e;
fix_the_problem();
}
}
if (!completed) {
reportError(lastException);
}
https://github.com/tusharmndr/retry-function-wrapper/tree/master/src/main/java/io
int MAX_RETRY = 3;
RetryUtil.<Boolean>retry(MAX_RETRY,() -> {
//Function to retry
return true;
});
Используйте петлю while
с локальным флагом status
. Инициализируйте флаг как false
и установите его на true
, когда операция успешна, например. ниже:
boolean success = false;
while(!success){
try{
some_instruction();
success = true;
} catch (NearlyUnexpectedException e){
fix_the_problem();
}
}
Это будет продолжать повторять попытку до его успешного завершения.
Если вы хотите повторить только определенное количество раз, используйте также счетчик:
boolean success = false;
int count = 0, MAX_TRIES = 10;
while(!success && count++ < MAX_TRIES){
try{
some_instruction();
success = true;
} catch (NearlyUnexpectedException e){
fix_the_problem();
}
}
if(!success){
//It wasn't successful after 10 retries
}
Это будет срабатывать максимум 10 раз, если не удастся до тех пор, пока он не выйдет, если он будет успешным перед рукой.