C++11部分特性

预定义宏

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"};
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容