目錄
環(huán)境準(zhǔn)備
被棄用的特性
常量字符串賦值需要使用const char*
與C的兼容性
語言可用性的強(qiáng)化
類型推導(dǎo)
區(qū)間迭代
列表初始化
模板增強(qiáng)
面對對象增強(qiáng)
語言運(yùn)行期的強(qiáng)化
Lambda表達(dá)式
std::function
std::bind/std::placeholder
右值引用
新增容器
智能指針和引用計(jì)數(shù)
RAII與引用計(jì)數(shù)
std::shared_ptr
std::unique_ptr
std::shared_ptr仍然無法解決的問題
環(huán)境準(zhǔn)備
在IDE工具中選擇編譯器,加入編譯命令 -std=c++11
被棄用的特性
(棄用暗示避免使用,但仍是標(biāo)準(zhǔn)庫的一部分)
char* str = "Hello world!";
這里的char*和const char*都是指向一個(gè)常量字符串,如果有另外一個(gè)char* str2指向的常量字符串和str一模一樣,那么其實(shí)str和str2也的地址是完全相同的,這有點(diǎn)類似java的常量池。
auto_ptr 被棄用,應(yīng)使用 unique_ptr 。
unique_ptr<A> a(new A[5]);
auto_ptr和unique_ptr的構(gòu)造函數(shù)都聲明為explicit,為了避免不知情的情況下出現(xiàn)的錯(cuò)誤,不能存在隱式轉(zhuǎn)換。
std::auto_ptr<A> a = new A(); //編譯錯(cuò)誤 std::auto_ptr<A> a(new A()); //編譯成功
關(guān)于explicit 更詳細(xì)的解釋 https://www.cnblogs.com/cutepig/archive/2009/01/14/1375917.html
auto_ptr和unique_ptr一樣不能處理數(shù)組,因?yàn)樗鼈兾鰳?gòu)的時(shí)候,都只是delete ptr,而不是delete []ptr。
-
register 關(guān)鍵字被棄用。 - C 語言風(fēng)格的類型轉(zhuǎn)換被棄用,應(yīng)該使用
static_cast 、reinterpret_cast 、const_cast 來進(jìn)行類型轉(zhuǎn)換
與C的兼容性
C++不是C的一個(gè)超集,在編寫C++時(shí),也應(yīng)該盡可能地避免諸如void *之類的程序風(fēng)格,而在不得不使用C時(shí),應(yīng)該使用extern "C"這種特性,將C語言的代碼與C++代碼進(jìn)行分離編譯,再統(tǒng)一鏈接這種做法。
https://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html
語言可用性的強(qiáng)化
nullptr用來區(qū)分空指針和0,和傳統(tǒng)C++會(huì)把NULL、0視為同一種東西,這會(huì)在C++中重載特性中發(fā)生混亂。
constexpr用來修飾一段代碼,說明該函數(shù)在編譯時(shí)便一定是個(gè)常數(shù),便于編譯器優(yōu)化。
// constexpr 聲明factorial可以參與編譯期的運(yùn)算 constexpr int factorial(int n) return n <= 1? 1 : (n * factorial(n - 1)); constN<factorial(4)> out1; // computed at compile time
volatile int k = 8; // disallow optimization using volatile std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time
類型推導(dǎo)
C++11引入了auto和decltype
template<typename T, typename U> auto add(T x, U y) -> decltype(x+y) {
template<typename T, typename U>
區(qū)間迭代
int array[] = {1,2,3,4,5}; std::cout << x << std::endl;
int array[] = {1,2,3,4,5}; std::cout << x << std::endl;
// & 啟用了引用, 如果沒有則對 arr 中的元素只能讀取不能修改 std::cout << i << std::endl;
列表初始化
可以用一種統(tǒng)一的方式對數(shù)組,結(jié)構(gòu)體,類和所有STL容器進(jìn)行初始化。
Foo(int, int){ cout << "Foo construction"; } int arr[] = { 1, 2, 3, 4, 5 }; std::map < int, int > map_t { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } }; std::list<std::string> list_str{ "hello", "world", "china" }; std::vector<double> vec_d { 0.0,0.1,0.2,0.3,0.4,0.5};
也可以列表初始化構(gòu)造函數(shù),列表還可以作為普通函數(shù)的形參。
#include <initializer_list>
Magic(std::initializer_list<int> list) {}
Magic magic = {1,2,3,4,5}; std::vector<int> v = {1, 2, 3, 4}
void func(std::initializer_list<int> list) {
統(tǒng)一的語法來初始化任意對象
B(int _a, float _b): a(_a), b(_b) {}
A a {1, 1.1}; // 統(tǒng)一的初始化語法
模板增強(qiáng)
在傳統(tǒng) C++ 的編譯器中,>> 一律被當(dāng)做右移運(yùn)算符來進(jìn)行處理。但實(shí)際上我們很容易就寫出了嵌套模板的代碼:
std::vector<std::vector<int>> wow;
這在傳統(tǒng)C++編譯器下是不能夠被編譯的,而 C++11 開始,連續(xù)的右尖括號(hào)將變得合法,并且能夠順利通過編譯。
在了解類型別名模板之前,需要理解『模板』和『類型』之間的不同。仔細(xì)體會(huì)這句話:模板是用來產(chǎn)生類型的。在傳統(tǒng) C++中,typedef 可以為類型定義一個(gè)新的名稱,但是卻沒有辦法為模板定義一個(gè)新的名稱。因?yàn)椋0宀皇穷愋?。例如?/p>
template< typename T, typename U, int value> SuckType():a(value),b(value){} typedef SuckType<std::vector<int>, U, 1> NewType; // 不合法
C++11 使用 using 引入了下面這種形式的寫法,并且同時(shí)支持對傳統(tǒng) typedef 相同的功效:
通常我們使用 typedef 定義別名的語法是:typedef 原名稱 新名稱; ,但是對函數(shù)指針等別名的定義語法卻不相同,這通常給直接閱讀造成了一定程度的困難。
typedef int (*process)(void *); // 定義了一個(gè)返回類型為 int,參數(shù)為 void* 的函數(shù)指針類型,名字叫做 process using process = int(*)(void *); // 同上, 更加直觀
using NewType = SuckType<int, T, 1>; // 合法
template<typename... TS> class Magic;
獲取參數(shù)個(gè)數(shù)
template<typename ...Args> std::cout << sizeof...(args) << std::endl;
對參數(shù)進(jìn)行解包
std::cout << value << std::endl;
template<typename T, typename ...Args> void printf(T value, Args... args) std::cout << value << std::endl;
列表初始化展開
template<typename T, typename... Argsa> auto print(T value, Args... args) std::cout<<value<<std::endl; return std::initializer_list<T> {([&]{std::cout<<args<<std::endl;}(), value)...};
變長參數(shù)模板示例,求最大值
template<typename T,typename... Args> T max(T a, T b, Args... args)
std::cout<<max(1,5,3,2,11);
模板增強(qiáng)可見https://blog.csdn.net/tennysonsky/article/details/77389891
面對對象增強(qiáng)
- 委托構(gòu)造,同一個(gè)類中一個(gè)構(gòu)造函數(shù)調(diào)用另一個(gè)構(gòu)造函數(shù)
- 繼承構(gòu)造,避免參數(shù)傳遞
- 顯式虛函數(shù)重載,override,final
- 顯式禁用默認(rèn)函數(shù)
語言運(yùn)行期的強(qiáng)化
Lambda表達(dá)式
auto basicLambda = [] {std::cout << "Hello, world!" <<endl;};
捕獲分為引用捕獲[&]和值捕獲[=],可以讓編譯器自行推導(dǎo)應(yīng)用列表。
參數(shù)寫在[](參數(shù)),在C++14中類型可以使用auto。
auto process = [&](int a, int b){std::cout<<(a+b)*c<"\n";};
Lambda表達(dá)式又稱為匿名函數(shù),有時(shí)候也無需指定其名字而直接調(diào)用。
[&](){std::cout<<"Hello world!\n"}();
std::function
C++11 std::function是一種通用、多態(tài)的函數(shù)封裝,它的實(shí)例可以對任何可以調(diào)用的目標(biāo)實(shí)體進(jìn)行存儲(chǔ),復(fù)制和調(diào)用操作,它也是一種類型安全的函數(shù)的容器。
// std::function 包裝了一個(gè)返回值為 int, 參數(shù)為 int 的函數(shù) std::function<int(int)> func = foo;
std::function<int(int)> func2 = [&](int value){ return 1 + value + important; std::cout << func(10) << std::endl; std::cout << func2(10) << std::endl;
std::bind/std::placeholder
int foo(int a, int b, int c)
//std::placeholders::_1表示對第一個(gè)參數(shù)占位 auto bindFoo = std::bind(foo, std::placeholders::_1, 1, 2);
右值引用
右值引用(及其支持的Move語意和完美轉(zhuǎn)發(fā))是C++11加入的重大語言特性之一。從實(shí)踐角度講,它能夠完美解決C++
中長久以來為人詬病的臨時(shí)對象效率問題。從語言本身講,它健全了C++中的引用類型在左值右值方面的缺陷。
為了測試,在編譯時(shí)設(shè)置編譯選項(xiàng)
-fno-elide-constructors
A() { std::cout << "Constructor" << std::endl; } A(const A&) { std::cout << "Copy Constructor" << std::endl; }
std::cout<<i<<" "<<j<<"\n";
如圖,在這種情況下,調(diào)用了一次構(gòu)造函數(shù),return時(shí)調(diào)用了一次拷貝構(gòu)造函數(shù)生成了一個(gè)臨時(shí)的a,將它return回的時(shí)候返回給了main函數(shù)中的a,隨機(jī)這個(gè)臨時(shí)的a也就消失了。這個(gè)階段浪費(fèi)了不少的性能。
A &&a = getA();
但如果將它改成了右值引用,就只會(huì)調(diào)用一次拷貝構(gòu)造函數(shù)用于生成臨時(shí)的變量,臨時(shí)的變量生命周期和右值引用的生命周期相等。
還有有關(guān)右值引用與深拷貝和轉(zhuǎn)發(fā)詳細(xì)可以參見https://www.cnblogs.com/qicosmos/p/4283455.html
新增容器
智能指針和引用計(jì)數(shù)
RAII與引用計(jì)數(shù)
引用計(jì)數(shù)這種計(jì)數(shù)是為了防止內(nèi)存泄露而產(chǎn)生的?;鞠敕ㄊ菍τ趧?dòng)態(tài)分配的對象,進(jìn)行引用計(jì)數(shù),每當(dāng)增加一次對同一個(gè)對象的引用,那么引用對象的引用計(jì)數(shù)就會(huì)增加一次,每刪除一次引用,引用計(jì)數(shù)就會(huì)減一,當(dāng)一個(gè)對象的引用計(jì)數(shù)減為零時(shí),就自動(dòng)刪除指向的堆內(nèi)存。
引用計(jì)數(shù)不是垃圾回收,引用技術(shù)能夠盡快收回不再被使用的對象,同時(shí)在回收的過程中也不會(huì)造成長時(shí)間的等待,更能夠清晰明確的表明資源的生命周期。
std::shared_ptr
auto pointer = std::make_shared<int>(10); int *p = pointer.get(); //這樣不會(huì)增加引用計(jì)數(shù)
std::cout<<pointer.use_count()<<std::endl;
std::unique_ptr
獨(dú)占指針,類似于之前的auto_ptr,
std::shared_ptr仍然無法解決的問題
std::shared_ptr<B> pointer; std::cout << "A 被銷毀" << std::endl; std::shared_ptr<A> pointer; std::cout << "B 被銷毀" << std::endl; std::shared_ptr<A> a = std::make_shared<A>(); std::shared_ptr<B> b = std::make_shared<B>();
|