一、程序的错误控制
在实际的开发中,往往会遇到一些基础的控制,比如是否数组越界,或者类型不匹配等。一般可以使用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++的路来。