Отображение кодов ошибок в строку в переполнении стека

Что может быть более эффективным способом отображения кодов ошибок из перечисления в строку? (в C ++)

Например, сейчас я делаю что-то вроде этого:

std::string ErrorCodeToString(enum errorCode)
{
switch (errorCode)
{
case ERROR_ONE:   return "ERROR_ONE";
case ERROR_TWO:   return "ERROR_TWO";
...
default:
break;
}

return "UNKNOWN";
}

Было бы эффективнее, если бы я сделал что-то подобное?

#define ToStr( name ) # name;

std::string MapError(enum errorCode)
{
switch (errorCode)
{
case ERROR_ONE:   return ToStr(ERROR_ONE);
case ERROR_TWO:   return ToStr(ERROR_TWO);
...
default:
break;
}

return "UNKNOWN";
}

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

4

Решение

Если вы собираетесь использовать макрос, почему бы не пройти весь путь:

std::string MapError(enum errorCode)
{
#define MAP_ERROR_CODE(code) case code: return #code ;
switch (errorCode)
{
MAP_ERROR_CODE(ERROR_ONE)
MAP_ERROR_CODE(ERROR_TWO)
...
}
#undef MAP_ERROR_CODE
return "UNKNOWN";
}
7

Другие решения

Я хотел, чтобы код ошибки (int) и описание строки (любая строка) были объявлены в одном-единственном месте, и ни один из приведенных выше примеров не позволяет этого.

Поэтому я объявил простой класс, хранящий как int, так и string, и поддерживающий статическую карту для преобразования int-> string. Я также добавил функцию auto-cast to int:

class Error
{
public:
Error( int _value, const std::string& _str )
{
value = _value;
message = _str;
#ifdef _DEBUG
ErrorMap::iterator found = GetErrorMap().find( value );
if ( found != GetErrorMap().end() )
assert( found->second == message );
#endif
GetErrorMap()[value] = message;
}

// auto-cast Error to integer error code
operator int() { return value; }

private:
int value;
std::string message;

typedef std::map<int,std::string> ErrorMap;
static ErrorMap& GetErrorMap()
{
static ErrorMap errMap;
return errMap;
}

public:

static std::string GetErrorString( int value )
{
ErrorMap::iterator found = GetErrorMap().find( value );
if ( found == GetErrorMap().end() )
{
assert( false );
return "";
}
else
{
return found->second;
}
}
};

Затем вы просто объявляете свои коды ошибок, как показано ниже:

static Error ERROR_SUCCESS(                 0, "The operation succeeded" );
static Error ERROR_SYSTEM_NOT_INITIALIZED(  1, "System is not initialised yet" );
static Error ERROR_INTERNAL(                2, "Internal error" );
static Error ERROR_NOT_IMPLEMENTED(         3, "Function not implemented yet" );

Затем любая функция, возвращающая int, может сделать, чтобы вернуть 1

return ERROR_SYSTEM_NOT_INITIALIZED;

И клиентские программы вашей библиотеки получат «Система еще не инициализирована» при вызове

Error::GetErrorString( 1 );

или же:

Error::GetErrorString( ERROR_SYSTEM_NOT_INITIALIZED );

Единственное ограничение, которое я вижу, состоит в том, что статические объекты Error создаются много раз, если файл .h, объявляющий их, включен во многие .cpp (поэтому я выполняю тест _DEBUG в конструкторе, чтобы проверить согласованность карты). Если у вас нет тысячи кодов ошибок, это не должно быть проблемой (и может быть обходной путь …)

5

enum errors {
error_zero,
error_one,
error_two
};

namespace {
const char *error_names[] = {
"Error one",
"Error two",
"Error three"};
}

std::string map_error(errors err) {
return error_names[err];
}
4

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

  1. У вас явно есть дублирование между errorCode enum, и эта функция.
  2. У вас также есть своего рода дублирование в вашей функции, так как значение перечисления имеет то же имя, что и строка.

Вы можете исправить оба с небольшим волшебством препроцессора:

// This is your definition of available error codes
#define ERROR_CODES \
ERROR_CODE(ERROR_ONE) \
ERROR_CODE(ERROR_TWO) \
ERROR_CODE(ERROR_THREE)

// Define ERROR_CODE macro appropriately to get a nice enum definition
#define ERROR_CODE(a) ,a
enum ErrorCode {
None,
ERROR_CODES
};
#undef ERROR_CODE

// Define ERROR_CODE macro differently here to get the enum -> string mapping
std::string MapError(enum errorCode)
{
#define ERROR_CODE(a) case a: return #a;

switch (errorCode)
{
case None: return "None";
ERROR_CODES
}
}
4

Нет, после того, как препроцессор передаст ваш код, они будут точно такими же. Единственное, второй подход был бы менее подвержен ошибкам при опечатках.

Я бы сказал, что то, что вы реализовали, уже является хорошим решением.

2

Я знаю, что это старый поток, но мне понравился подход Фрериха Раабе, и я получил его для работы в VS без ошибок:

#define ERROR_CODES \
ERROR_CODE(NO_ERROR) \
ERROR_CODE(ERROR_ONE) \
ERROR_CODE(ERROR_TWO) \
ERROR_CODE(ERROR_THREE) \
ERROR_CODE(ERROR_FOUR)

#define ERROR_CODE(code) code,
typedef enum { ERROR_CODES } ErrorCodes;
#undef ERROR_CODE

const char *MapError(const int errorCode)
{
#define ERROR_CODE(code) case code: return #code;
switch (errorCode)
{
ERROR_CODES
default: return "UNKNOWN ERROR";
};
#undef ERROR_CODE
}
1
По вопросам рекламы [email protected]