1. C++语言历程
C++语言从1983年正式诞生以来,经历了多次的修订与改版,主要从包含两个大的节点,一是1998年,C++语言正式被C++标准委员会纳入标准,二是2011年,C++语言新增了许多新的特性,大大提升C++语言的实用性。可以把C++标准分成两个大的版本,C++1.0(C++98,C++03,C++03(tr1))和C++2.0(C++11,C++14,C++17,C++20(草案)) C++1.0和2.0的主要特性
C++版本
特性
C++98
主要集成在兼容C特性的基础上增加面向对象的特性,包括类、简单继承、内联机制、函数默认参数以及强类型检查,虚函数、函数重载、引用机制(符号为&)、const关键字以及双斜线的单行注释,多重继承、保护成员以及静态成员等特性,并集成了标准模板库STL
C++03
主要修订C++98中存在的问题
C++03(tr1)
发布C++希望引入新特性的报告,但没有完全引入,后期加入部分std::tr1相关的功能
C++11
新增正则表达式(正则表达式详情)、完备的随机数生成函数库、新的时间相关函数,原子操作支持、标准线程库(2011之前,C和C++语言均缺少对线程的支持)、一种能够和某些语言中foreach语句达到相同效果的新的for语法、auto关键字、新的容器类、更好的union支持、数组初始化列表的支持以及变参模板的支持等等新特性
C++14
主要对C++11变准文案描述进行了修正
C++17
简化C++语言的日常使用
C++20
–
2. 各编译器对C++标准核心功能的支持
C++11核心功能
MSVC
GCC
ICC
Clang
替代方案
Rvalue references
10.0
4.3
12.0
2.9
Boost.Move
Rvalue references for *this
Nov 13
4.8.1
14.0
2.9
Initialization of class objects by rvalues
9.0
4.3
11.1
2.9
Non-static data member initializers
12.0
4.7
14.0
3.0
Variadic templates
Nov 12
4.3
12.1
2.9
Extending variadic template template parameters
Nov 12
4.4
12.1
2.9
Initializer lists
Nov 12
4.4
14.0
3.1
Static assertions
10.0
4.3
11.1
2.9
Boost.StaticAssert
auto-typed variables
10.0
4.4
12.0
2.9
Boost.Typeof
Multi-declarator auto
10.0
4.4
12.0
2.9
Boost.Typeof
Removal of auto as a storage-class specifier
10.0
4.4
12.0
2.9
Boost.Typeof
New function declarator syntax
10.0
4.4
12.0
2.9
Boost.ReturnType
New wording for C++11 lambdas
10.0
4.5
12.0
3.1
Boost.Lambda
Declared type of an expression
10.0
4.3
12.0
2.9
Boost.Typeof
Incomplete return types
11.0
4.8.1
12.1
3.1
Right angle brackets
9.0
4.3
11.1
2.9
TR1
Default template arguments for function templates
Nov 12
4.3
12.1
2.9
Solving the SFINAE problem for expressions
No
4.4
12.1
2.9
Template aliases
12.0
4.7
12.1
3.0
Extern templates
9.0
4.3
11.1
2.9
Null pointer constant
10.0
4.6
12.1
3.0
自己实现的null_ptr
Strongly-typed enums
11.0
4.4
14.0
2.9
#define
Forward declarations for enums
11.0
4.6
14.0
3.1
Generalized attributes
14.0
4.8
12.1
3.3
Generalized constant expressions
Nov 13
4.6
14.0
3.1
Alignment support
Nov 13
4.8
No
3.3
Delegating constructors
Nov 12
4.7
14.0
3.0
Inheriting constructors
Nov 13
4.8
15.0
3.3
Explicit conversion operators
Nov 12
4.5
14.0
3.0
New character types
14.0
4.4
14.0
2.9
Unicode string literals
14.0
4.5
14.0
3.0
Raw string literals
Nov 12
4.5
14.0
3.0
Universal character name literals
14.0
4.5
12.1
3.1
User-defined literals
VS14 CTP1
4.7
15.0
3.1
Standard Layout Types
11.0
4.5
No
3.0
Defaulted and deleted functions
12.0
4.4
12.0
3.0
Extended friend declarations
10.0
4.7
12.0
2.9
Extending sizeof
Nov 13
4.4
14.0
3.1
Inline namespaces
14.0
4.4
14.0
2.9
Unrestricted unions
14.0
4.6
14.0
3.1
Local and unnamed types as template arguments
9.0
4.5
12.0
2.9
Range-based for
11.0
4.6
13.0
3.0
Boost.Foreach
Explicit virtual overrides
11.0
4.7
14.0
3.0
#define
Minimal support for garbage collection and reachability-based leak detection
10.0
No
No
No
Allowing move constructors to throw [noexcept]
Nov 13
4.6
14.0
3.0
Defining move special member functions
14.0
4.6
14.0
3.0
Sequence points
12.0
4.8
15.0
3.3
Atomic operations
11.0
4.4
13.0
3.1
Boost.Atomic
Strong Compare and Exchange
11.0
4.8
13.0
3.1
Boost.Atomic
Bidirectional Fences
11.0
4.8
13.0
3.1
Boost.Atomic
Memory model
12.0
4.8
No
3.2
Boost.Atomic
Data-dependency ordering: atomics and memory model
11.0
4.8
No
3.2
Boost.Atomic
Propagating exceptions
10.0
4.4
12.0
2.9
Boost.Exception
Abandoning a process and at_quick_exit
14.0
4.8
No
No
Allow atomics use in signal handlers
12.0
4.8
No
3.1
Thread-local storage
14.0
4.8
No
3.3
Boost.Thread
Dynamic initialization and destruction with concurrency
Nov 13
4.8
No
2.9
func predefined identifier
Nov 13
4.3
11.1
2.9
FUNCTION
C99 preprocessor
No
4.3
11.1
2.9
long long
9.0
4.3
11.1
2.9
__int64
Extended integral types
No
No
No
No
C++14核心功能
MSVC
GCC
ICC
Clang
替代方案
Tweak to certain C++ contextual conversions
12.0
4.9
16.0
3.4
Binary literals
14.0
4.9
11.0
2.9
Return type deduction for normal functions
Nov 13
4.9
15.0
3.3
Generalized lambda capture (init-capture)
14.0
4.9
15.0
3.4
Generic (polymorphic) lambda expressions
Nov 13
4.9
16.0
3.4
Variable templates
15.0
5.0
No
3.4
Relaxing requirements on constexpr functions
15.0
5.0
No
3.4
Member initializers and aggregates
15.0
5.0
16.0
3.3
Clarifying memory allocation
No
No
No
3.4
Sized deallocation
14.0
5.0
17.0
3.4
[[deprecated]] attribute
14.0
4.9
16.0
3.4
Single-quotation-mark as a digit separator
14.0
4.9
16.0
3.4
C++17核心功能
MSVC
GCC
ICC
Clang
替代方案
static_assert with no message
15.0
6
No
3.5
C++11’s static_assert
Disabling trigraph expansion by default
12.0
5.1
No
3.5
typename in a template template parameter
14.0
5
17.0
3.5
New auto rules for direct-list-initialization
14.0
5
17.0
3.8
Fold expressions
No
6
No
3.6
Attributes for namespaces and enumerators
14.0
6
No
3.6
u8 character literals
14.0
6
17.0
3.6
Nested namespace definition
15.0
6
17.0
3.6
Allow constant evaluation for all non-type template arguments
No
6
No
3.6
Remove deprecated register storage class
No
7
No
3.8
Remove deprecated bool increment
No
7
No
3.8
Make exception specifications part of the type system
No
7
No
No
__has_include in preprocessor conditionals
No
5
No
Yes
New specification for inheriting constructors (DR1941 et al)
No
7
No
3.9
[[fallthrough]] attribute
15.0
7
No
3.9
[[nodiscard]] attribute
No
7
No
3.9
[[maybe_unused]] attribute
No
7
No
3.9
Aggregate initialization of classes with base classes
No
7
No
3.9
constexpr lambda expressions
No
7
No
No
Unary Folds and Empty Parameter Packs
No
6
No
3.9
Differing begin and end types in range-based for
15.0
6
No
3.9
Lambda capture of *this
No
7
No
3.9
Direct-list-initialization of enums
No
7
No
3.9
Hexadecimal floating-point literals
No
3.0
No
Yes
Using attribute namespaces without repetition
No
7
No
3.9
Dynamic memory allocation for over-aligned data
No
7
No
No
Template argument deduction for class templates
No
7
No
No
Non-type template parameters with auto type
No
7
No
No
Guaranteed copy elision
No
7
No
No
Stricter expression evaluation order
No
7
No
No
Requirement to ignore unknown attributes
No
Yes
No
Yes
constexpr if-statements
No
7
No
3.9
Inline variables
No
7
No
3.9
Structured bindings
No
7
No
No
Separate variable and condition for if and switch
No
7
No
3.9
Matching template template parameters to compatible arguments
No
7
No
No
Removing deprecated dynamic exception specifications
No
7
No
No
Pack expansions in using-declarations
No
No
No
No
3. c++11核心功能
3.1 可变参数模板(Variadic Template)
主要增加关键字…, 表示一个组或者包,代表可变的参数个数或类型
从模板函数上来看,可以更好的完成递归函数的调用,具体如代码example1
从类模板的角度看,可以更方便的完成递归继承,具体如代码example2
example1 函数模板
//注意必须配一个无参的print函数,否则递归没有边界
void print()
{
}
//定义一个模板函数 1 + n, 更具化,
//(1)... 表示一个所谓的包(pack),一组
//(2)typename... Types 模板参数包
//(3)const Types&... args 函数参数类型包
//(4)args... 参数包
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args)
{
std::cout<<"i'm 1+n"<<std::endl;
std::cout<<firstArg<<std::endl;
//递归()
print(args...);
}
//n 更泛化,优先调用更具化的模板函数
template <typename... Types>
void print(const Types&... args)
{
std::cout<<"i'm n"<<std::endl;
//递归
print(args...);
}
example2 类模板
//注意,一定要先加这一句
template <typename... Values> class MytestClassTem;
template<> class MytestClassTem<>{};
template<typename First,typename... others>
class MytestClassTem<First, others...>
: private MytestClassTem<others...>
{
typedef MytestClassTem<others...> inherited;
public:
MytestClassTem(){}
MytestClassTem(First v, others... args)
:m_first(v), inherited(args...){}
First first(){return m_first;}
//此处返回的是父类的实例
inherited& other(){return *this;}
protected:
First m_first;
};
/调用
MytestClassTem<int ,float,std::string> obj(41, 6.3, "hello");
std::cout<<"子级:"<<obj.first()<<std::endl;
std::cout<<"子级的上一级:"<<obj.other().first()<<std::endl;
3.2 右尖括号(Right Angle Brackets)
#include <vector>
typedef std::vector<std::vector<int> > Table; // OK
typedef std::vector<std::vector<bool>> Flags; // Error
#include <vector>
typedef std::vector<std::vector<int> > Table; // OK
typedef std::vector<std::vector<bool>> Flags; // OK
3.3 空指针(nullptr)
C++11之前没有关键字nullptr(其对应的类型为std::nullptr_t)
nullptr用于替换0或者NULL,因为NULL本身是定义为0的,有时候使用会产生歧义
fun(0);//call fun(int)
int i = NULL;
fun(i);//call fun(int)
char* pp = NULL;
fun(pp);//call fun(void*)
fun(NULL);//有歧义
fun(nullptr);//call fun(void*)
3.4 auto关键字
在C++11中,可以auto定义变量,而不指定变量的类型
编译器会从等号右边的表达式或变量来推断auto变量的类型
auto 一般用于替代变量类型名字太长,或表达式类型太复杂的场景
//简单类型不建议使用auto
auto data = 2;
//typeid包含在#include <typeinfo>
std::cout<<typeid(data).name()<<std::endl;//i --- int
auto res = f();
std::cout<<typeid(res).name()<<std::endl;//f -- float
//auto 一般用于替代变量类型名字太长,或表达式类型太复杂的场景
std::vector<std::string> vecStr;
auto itr = vecStr.begin(); //auto取代 std::vector<std::string>::iterator itr = vecStr.begin()
auto lam = [](int x)->bool{return x = 0;}; // auto取代lambda表达式的类型
3.5 统一初始化(Uniform Initialization)
C++11之前,有三种为变量或对象初始化的方式,大括号,小括号, 赋值符号
C++ 11 引入统一的初始化方式 ————统一使用大括号,内部编译器会进行转换,编译器会在识别到{t1,t2,…,tn}时,自动保存至一个initializer_list对象中,并关联至一个一个array<T,n>,在调用构造函数时,会将array中的元素逐一分解传递给构造函数
若构造函数的入参为initializer_list时,则不做分解,直接整包传进去
class TestInitializerList
{
public:
TestInitializerList(int a, int b)
{
std::cout<<"TestInitializerList(int,int), a = "<<a<<",b="<<b<<std::endl;
}
TestInitializerList(std::initializer_list<int> initList)
{
std::cout<<"TestInitializerList(initializer_list<int> initList) ,vals = ";
for(auto i : initList)
{
std::cout<<i<<",";
}
std::cout<<std::endl;
}
};
TestInitializerList a(77,5);//call TestInitializerList(int a, int b)
TestInitializerList b{65,9};//若包含std::initializer_list<int>的构造函数存在,则调用,如不存在,则逐一分解,调用构造函数TestInitializerList(int a, int b)
TestInitializerList c{34,56,78};若包含std::initializer_list<int>的构造函数存在,则调用,则分解,分解后若有匹配的构造函数则调用,没有匹配的会报错
TestInitializerList d={67,90};//同d{65,9};
C++11也兼容之前的小括号和赋值符号的初始化方式
before C++11
//小括号
Rect r(3,4);
r.printRect();
//大括号
int ia[2] = {3,4};
//赋值符号
Rect r1 = {4,5};//在C++11之前只能使用构造函数来对对象初始化
r1.printRect();
//C++11 Uniform Initializzation
int ib[2]{6,7};
std::vector<int> vec{8,9};
Rect r2{3,9};
r2.printRect();
C++11引入统一的初始化对象或变量的方式,其主要目的是构造对象时可接收可变的参数,在标准库的设计上提供了很大的便利.
引入了std::initializer_list<>模板类,其内部维护了一个std::array数据
//有了Initializer List后,直接不限个数,#include<algorithm>
std::cout<<std::max({1,2,3,4,5})<<std::endl;
//有了Initializer List后,直接不限个数,#include<algorithm>
std::cout<<std::min({1,2,3,4,5})<<std::endl;
int i;//i有一个未定义的值
std::cout<<i<<std::endl;
int j{};//j被初始化为0
std::cout<<j<<std::endl;
char* p;//p有一个未定义的指针值
std::cout<<p<<std::endl;
char* q{};//q=nullptr
std::cout<<q<<std::endl;
int i(5.3);//将浮点型强制转换成整型
std::cout<<i<<std::endl;
int j{5.0};//不会将浮点型强制转换成整型
std::cout<<j<<std::endl;
char p{8};//OK
std::cout<<p<<std::endl;
char q{99999};//99999不在char范围内,无法强制转换
std::cout<<q<<std::endl;
3.6 关键字explicit
explicit含义是明确的,显示的,一般用在构造函数前面,但在C++11之前,只能放在包含一个入参的构造函数前面
struct TestExplicit
{
explicit TestExplicit(int re, int im = 0):real(re),imag(im)
{}
TestExplicit operator+(const TestExplicit& x)
{
return TestExplicit((real+x.real),(imag+x.imag));
}
int real;
int imag;
};
TestExplicit a(12,5);
std::cout<<a.real<<","<<a.imag<<std::endl;
//编译器自动调用TestExplicit(int re, int im = 0)将int 5转换为TestExplicit对象
//若加上explicit ,则调用TestExplicit(int re, int im = 0)时需要更加明确,不能默认将int 转换为则调用TestExplicit
TestExplicit b = a + 5;
std::cout<<b.real<<","<<b.imag<<std::endl;
C++11中允许explicit放在包含多个入参的构造函数前面(其实是基于Uniform Initialization,扩展了其功能)
class TestNewExplicit
{
public:
TestNewExplicit(int a,int b)
{
std::cout<<"TestNewExplicit(int a,int b), a = "<<a<<",b="<<b<<std::endl;
}
TestNewExplicit(std::initializer_list<int> initList)
{
std::cout<<"TestNewExplicit(std::initializer_list<int> initList) ,vals = ";
for(auto i : initList)
{
std::cout<<i<<",";
}
std::cout<<std::endl;
}
explicit TestNewExplicit(int a,int b,int c)
{
std::cout<<"explicit TestNewExplicit(int a,int b,int c), a = "<<a<<",b="<<b<<",c="<<c<<std::endl;
}
};
TestNewExplicit p1(77,5);
TestNewExplicit p2{77,5};
//TestNewExplicit p3{77,5,99,88};
//若不存在接收std::initializer_list<int>参数的构造函数,则需要编译器自动分解,匹配个数进行调用相应参数的构造函数
//若分解匹配后的构造函数前面加了explicit,则不能直接调用
//converting to 'TestNewExplicit' from initializer list to TestNewExplicit
TestNewExplicit p4 = {1,2,3};
3.7 基于范围的for循环(range-based for statement)
从容器中依次取出元素进行处理
接收者为引用时,则用一个指针指向容器中的元素,不需要拷贝一份
for(int i : {1,2,3,4})
{
std::cout<<i<<std::endl;
}
std::vector<int> vec{4,5,6};
for(auto& j : vec)
{
std::cout<<j<<std::endl;
std::cout<<"j的地址:"<<&j<<",vec[0]的地址"<<&vec[0]<<std::endl;
}
3.8 =default/=delete
Big-Three:表示类中默认的析构函数,拷贝构造函数,operator=(C++11中引入右值引用后,增加了移动拷贝构造函数,移动operator=, 被称为Big-Five),这些函数不能被重载
=default ,只能被用在Big-Five函数后面,表示使用编译器默认的函数
=delete, 一般用在Big-Five函数后面,但也可以使用在其他普通函数函数后面,表示告知编译器不要定义该函数(建议不要用在析构函数上)
class Test
{
public:
//不能使用编译器默认的构造函数
Test() = delete;
Test(int a)
{
std::cout<<"Test(int a)"<<std::endl;
}
};
class Zoo
{
public:
//自定义构造函数
Zoo(int i1,int i2):d1(i1),d2(i2)
{}
//拷贝构造函数,被删除
Zoo(const Zoo&) = delete;
//移动构造函数 使用编译器默认的
Zoo(Zoo&&) = default;
//赋值运算符 使用编译器默认的
Zoo& operator=(const Zoo&) = default;
//移动赋值运算符 被删除
Zoo& operator=(const Zoo&&) = delete;
virtual ~Zoo(){}
}
附:经典网站及书籍
名称
说明
C++14标准PDF
https://doc.imzlp.me/viewer.html?file=docs/standard/isocpp2014.pdf
C++11标准PDF
https://doc.imzlp.me/viewer.html?file=docs/standard/isoc11.pdf
多种编译器对C++11的支持
http://www.klayge.org/wiki/index.php/多种编译器对C%2B%2B11的支持
多种编译器对C++14的支持
http://www.klayge.org/wiki/index.php/多种编译器对C%2B%2B14的支持
多种编译器对C++17的支持
http://www.klayge.org/wiki/index.php/多种编译器对C%2B%2B17的支持
在线开发环境
https://wandbox.org/
各VS版本对C++11功能的支持
https://blog.csdn.net/xiaomu_347/article/details/82563688
侯捷老师的《C++11新特性》视频
https://www.bilibili.com/video/av51863195/?p=9