C++开发小技巧

C++开发一些小技巧

积累一些能用得到的C++开发小技巧。

错误码/状态码

错误码/状态码在项目很常见,用于提示错误类型、状态,通常还会附带一些相关描述。通常错误码是统一管理的,例如使用宏或者枚举定义。

平时我的做法

  • 使用宏或者枚举定义错误码、状态码
  • 使用map或者数组定义错误码的提示信息,通过GetMsg获取错误提示
namespace statis_code {
enum ServiceCode {
  kSuccess = 0,
  // client exccept
  kBadParams = 1000,
  kIllegalAuth = 1001,

  // service except
  kServerExcept = 2001
};

const std::unordered_map<ServiceCode, std::string> kCodeMsg{
    {kSuccess, "ok"},
    {kBadParams, "except request params,check uri"},
    {kIllegalAuth, "auth failed"},
    {kServerExcept, "service unavailable"}};

std::string GetMsg(ServiceCode code) {
  auto itr = kCodeMsg.find(code);
  return itr == kCodeMsg.end() ? "unknown status" : itr->second;
}
} // namespace statis_code

brpc的做法

上述做有几个不太好的地方,首先是错误码定义较为随意,有可能和系统错误码冲突.linux自身0-132有自己的定义;其次我们需要自己去保证错误码的不重复,当错误码较多且多人开发时可能会有冲突,但是这种冲突很难发现;用户可能还会继续拓展错误码,这时需要修改枚举和map。所以我们更希望: 错误码能在编译层面保证不重复;错误码定义希望是注册式的,提供给用户注册接口和获取msg接口。
无意间看到brpc定义错误码时使用了模板特例化保证不重复,同时也是注册式的写法。

  • 模板特例化的应用
    模板特例化
template <int status_code> class ServiceCodeHelper {};
template <> class ServiceCodeHelper<statis_code::ServiceCode::kBadParams> {};
template <> class ServiceCodeHelper<statis_code::ServiceCode::kBadParams> {}; // 报错,重复定义

通过模板特例化,可能在编译期间发现重复定义的错误码。那么接下来做法上第一种做法类似,注册错误码描述即可。下面是注册函数:
errno_desc数组存储对错误码的描述,在注册时先做范围检测、重复描述检测、是否系统错误码检测,然后将描述写入数组。

const int ERRNO_BEGIN = -32768;
const int ERRNO_END = 32768;
static const char* errno_desc[ERRNO_END - ERRNO_BEGIN] = {};
static pthread_mutex_t modify_desc_mutex = PTHREAD_MUTEX_INITIALIZER;

const size_t ERROR_BUFSIZE = 64;
__thread char tls_error_buf[ERROR_BUFSIZE];

int DescribeCustomizedErrno(
    int error_code, const char* error_name, const char* description) {
    BAIDU_SCOPED_LOCK(modify_desc_mutex);
    if (error_code < ERRNO_BEGIN || error_code >= ERRNO_END) {
        // error() is a non-portable GNU extension that should not be used.
        fprintf(stderr, "Fail to define %s(%d) which is out of range, abort.",
              error_name, error_code);
        _exit(1);
    }
    const char* desc = errno_desc[error_code - ERRNO_BEGIN];
    if (desc) {
        if (strcmp(desc, description) == 0) {
            fprintf(stderr, "WARNING: Detected shared library loading\n");
            return -1;
        }
    } else {
#if defined(OS_MACOSX)
        const int rc = strerror_r(error_code, tls_error_buf, ERROR_BUFSIZE);
        if (rc != EINVAL)
#else
        desc = strerror_r(error_code, tls_error_buf, ERROR_BUFSIZE);
        if (desc && strncmp(desc, "Unknown error", 13) != 0)
#endif
        {
            fprintf(stderr, "WARNING: Fail to define %s(%d) which is already defined as `%s'",
                    error_name, error_code, desc);
        }
    }
    errno_desc[error_code - ERRNO_BEGIN] = description;
    return 0;  // must
}

获取错误信息时首先查我们自己定义的数组然后再查是否时系统错误码。

const char* berror(int error_code) {
    if (error_code == -1) {
        return "General error -1";
    }
    if (error_code >= butil::ERRNO_BEGIN && error_code < butil::ERRNO_END) {
        const char* s = butil::errno_desc[error_code - butil::ERRNO_BEGIN];
        if (s) {
            return s;
        }
#if defined(OS_MACOSX)
        const int rc = strerror_r(error_code, butil::tls_error_buf, butil::ERROR_BUFSIZE);
        if (rc == 0 || rc == ERANGE/*bufsize is not long enough*/) {
            return butil::tls_error_buf;
        }
#else
        s = strerror_r(error_code, butil::tls_error_buf, butil::ERROR_BUFSIZE);
        if (s) {
            return s;
        }
#endif
    }
    snprintf(butil::tls_error_buf, butil::ERROR_BUFSIZE,
             "Unknown error %d", error_code);
    return butil::tls_error_buf;
}

错误码注册

#define BAIDU_CONCAT(a, b) BAIDU_CONCAT_HELPER(a, b)
#define BAIDU_CONCAT_HELPER(a, b) a##b

#define REGISTER_CODE(code, desp)                                              \
  \ 
const int BAIDU_CONCAT(error_code_flag, __LINE__) =                            \
      DescribeCustomizedErrno((code), (desp));                                 \
  template <> class ServiceCodeHelper<int(code)> {};

REGISTER_CODE(ServiceCode::kBadParams, "bad uri")
REGISTER_CODE(ServiceCode::kBadParams, "bad uri desp")  // 重复定义
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值