预定义宏
1. func预定义标识符
功能:返回所在函数的名字
C++11中甚至允许在类或结构体中使用:
#include<iostream>
using namespace std;
class TestStruct {
public:
TestStruct () : name(__func__) {}
const char *name;
};
int main() {
TestStruct ts;
cout << ts.name <<endl;
}
原理:编译器隐式地在函数定义后定义func表示符
所以需要注意的是func不能作为函数参数的默认值,因为在参数声明的时候,func还没有被定义
void testFun(string func_name = __func__) {}; //compile error
2.宏__cplusplus
C++11的__cplusplus被预定义为201103L,可以用
#ifdef __cplusplus < 201103L
#error "please use C++11 implementation"
#endif
进行检测
静态断言
assert函数是在运行时进行断言,而当需要在编译时断言则需要使用静态断言,在C++11中,引入了static_assert,接受两个参数,static_assert ( bool_constexpr , message )
一个是断言表达式(通常返回bool值),一个是警告信息
当然,利用“不能除以0”的性质也可以实现静态断言,但效果明显没有C++11标准中的好(毕竟标准直接报错警告信息,而这样实现只会报不能/0,这样还会增加调试难度)
#include<iostream>
#include<cstring>
using namespace std;
#define assert_static(e) \
do{ \
enum{ assert_static__ = 1/ (e) }; \
}while (0)
template <typename T, typename U> int bit_copy(T&a, U& b){
assert_static(sizeof(b) == sizeof(a));
}
int main(){
int a = 1;
double b = 3;
bit_copy(a,b);
}
noexcept修饰符与noexcept操作符
noexcept比throw()在效率上会高一些,在 C++11中,noexcept替代了throw()
noexcept修饰符
noexcept修饰符有两种形式,一种是直接加上关键字noexcept,而另外一种则可以接受一个常量表达式作为参数
void excpt_func() noexcept (常量表达式);
量表达式的结果会被转换成一个bool类型的值。该值为true,表示函数不会抛出异常,反之,则有可能抛出异常。这里,不带常量表达式的noexcept相当于声明了noexcept(true),即不会抛出异常。
在通常情况下,在C++11中使用noexcept可以有效地阻止异常的传播与扩散。
noexcept操作符
noexcept作为一个操作符时,通常可以用于模板。
我的测试代码:
#include<iostream>
#include<cstring>
using namespace std;
class Test{
public:
Test() {
throw 1;
cout<<"constructor"<<endl;
}
~Test() {
cout<<"dtor"<<endl;
}
};
template <class T>
void fun() noexcept(noexcept(T())) {
throw 1;
}
int main(){
try{
fun<Test>();
}
catch(...){
cout<<"caught"<<endl; //caught
}
try{
fun<int>();
}
catch(...){
cout<<"caught"<<endl; //terminate called after throwing an instance of 'int'
}
return 0;
}
noexcept(noexcept(T()))中,第二个noexcept就是一个noexcept操作符。当其参数是一个有可能抛出异常的表达式的时候,其返回值为false,反之为true(实际noexcept参数返回false还包括一些情况,这里就不展开讲了)。
对于测试代码中的例子,当模板实参为Test时,Test()可能抛出异常,所以这时候此时签名修饰符为noexcept(false),所以可以抛出异常
而当模板实参为int的时候,noexcept(noexcept(T()))为noexcept(true),所以这时候试图抛出异常的话,会直接调用std::terminate终端程序的执行
另外需要注意的是,析构函数默认为noexcept,delete函数默认为noexcept
快速初始化成员变量
C++11增加允许了使用=或者花括号{}的方式来初始化:
struct init{ int a = 1; double b {1.2}; };
这样的方式也叫就地初始化,然而有一个问题,这样的初始化方式与初始化列表是否冲突?
当然不会冲突:
class Test{
public:
Test(string ss = "234"):s(ss){}
string s {"123"};
};