在实际的开发中,往往会遇到一些基础的控制,比如是否数组越界,或者类型不匹配等。一般可以使用if语句来控制,但在一些重要的场景上使用assert或者其它一些自定义的宏(verify等 )。随着C++标准的不断推进,在新标准里又提供了在编译期进行判断的关键字static_assert。
有人可能会说,可以用异常来处理控制这些问题,但实际上,C/C++原则上是不推荐使用异常来处理问题的,除了其本身语言无法提供更多的堆栈信息等外,更重要的是,在C++程序中,一般到了这种地步,程序要么直接崩溃了(内存异常);要么,程序再跑已经没有任何意义。可能在某些特定场合下,程序捕获异常是有意义的,这就需要开发者自己处理了。
在运行期进行错误控制一般使用assert,基本的示例如下:
#include <assert.h>
#include <iostream>
#include <string>
#define SHOW_KLEN = 1
constexpr int KLEN = 100;
int buf[KLEN] = {0};
void testAssert(int id) {
assert(id < KLEN);
std::cout << "id value:" << id << std::endl;
}
int main() {
int index = 1000;
testAssert(index);
return 0;
}
但是使用assert的缺点在于,一旦出现问题,程序自动就挂了。然后会拿到一个assert的问题报告。如果此时用GDB去调试,发现崩溃的堆栈也在 assert上。所以其最好用于关键地方,一旦出问题,程序没有运行的必要了。
编译器控制有两种方式,一种是使用原来的#error,这种方式只会提供一个显示的错误标记。可以用在一些编译选项控制上,比如平台选择、OS选择等等。对于一些更精细的控制,可能就不太适合了。
#include <assert.h>
#include <iostream>
#include <string>
#define SHOW_KLEN = 1 //Code comments result in compilation errors
void testError(const std::string &s) {
#ifndef SHOW_KLEN
#error "do not insert db!"
#endif
if (s == "insert") {
//#error "do not insert db!"
}
std::cout << "operator is allow!" << std::endl;
}
int main() {
std::string op = "insert";
testError(op);
return 0;
}
另外一种就是使用static_assert,它主要是在编译期控制值,保证按需要进行处理。它一般在模板编程上应用更广,特别是在元编程中,它可能会起到一些重要的作用。
#include <assert.h>
#include <iostream>
#include <string>
#define SHOW_KLEN = 1 //Code comments result in compilation errors
constexpr int KLEN = 100;
void staticassert() {
static_assert(KLEN == 100);
// static_assert(KLEN > 100);//build err
}
template <int N> struct IsPower2 {
// Metaprogramming similar to (std:: is_integrial<T>:: value) can be used
static_assert(N > 8, "must N > 8");
static_assert((N & (N - 1)) == 0, "must power 2!");
};
template <class T> class Data {
public:
void GetData(const T &t) { static_assert(sizeof(T) <= sizeof(short), "Data type size not short"); }
};
void testData() {
Data<short> d;
Data<decltype(KLEN)> d1;
Data<std::decay_t<decltype(KLEN)>> d2;
d.GetData(2);
d1.GetData(KLEN);//build err
d2.GetData(KLEN);//build err
}
constexpr int D = 16;//Non 2 power rule error
int main() {
IsPower2<D>();
testData();
return 0;
}
其实写程序最重要的是学以致用,也就是常说的灵活运行知识。这三个基础的控制手段,特别是static_assert可以多看一下相关标准文档,再多看一下别人的代码,基本就能掌握,重点就是用。
C/C++一直是外人认为的难学的语言,原因提过,就是太灵活。学得灵活,用得灵活,这让许多初学者很难一下子适应过来。其实最简单路就是最基础的方式,把基础打好。侯捷老师的原话:“勿在浮沙筑高台!”,非常贴切。尤其这几年看标准文档,越看越发现,这句话的重要性。配合着侯老师的另外一句话:“源码之前,了无秘密”。就明白了学好C/C++的最简单的方式了,打好基础(多看理论知识),多看代码(多多上机实践)。总结出自己一套学用C/C++的路来。