Learning c++11 new features on the basis of c++98

Source: Internet
Author: User

I have been using the c++98 specification to program, for c++11 only to hear its name but not use its characteristics. Recently because of the needs of the work, need to master some of the characteristics of c++11 , so consulted some c++11 data. Because of their own c++98 Foundation, so from the c++98 transition to c++11 is not particularly difficult, read some books, is to c++11 have a comparative basis of understanding, It feels like programmers still have to keep updating new language features, and now the C + + standard is c++17 ! This article is a summary of some common new features of c++11 , with c++98 and c++11 differences in syntax to highlight the extraordinary advantages of c++11 new features.

First, new Syntax 1. Automatic type deduction auto

Auto derivation of auto, used to infer the data type of a variable from an initialization expression.

//C++98int a = 10;string s = "abc";float b = 10.0;vector<int> c;vector<vector<int> > d;map<int, string> m;m[1] = "aaa";map<int, string>::iterator it = m.begin();//C++11auto a1 = 10;  //a1为intauto s1 = "abc";  //s1为stringauto b1 = b;  auto c1 = c;auto d1 = d;auto e1 = ‘a‘;int* x = &a1;auto d1 = x;auto m1 = m.begin();auto x=1,y=2; //okauto i=1.j=3.14; //compile errordouble a2 = 3.144;const auto a3 = a2;  //const doubleauto a4 = a2;  //doublevolatile int c2 = 3;auto c3 = c2; //int
2. Extraction Type Decltype

Decltype can be typed by a variable or an expression.

#include <iostream>#include <vector>using namespace std;int add(int a){    return ++a;}void fun(int a){    cout << "call function: [int]\n" << endl;}void fun(int *a){    cout << "call function: [int*]\n" << endl;}int main(){    //C++11    int aa = 10;    decltype(aa) bb = 11;    string ss = "hello intel";    decltype(ss) ss1 = "hello";    const vector<int> vec(1);    decltype(vec[0]) cc = 1;    decltype(0) dd = vec[0];  //dd是int类型    decltype(add(1)) ee;  //int    int a[5];    decltype(a) ff; //int[5]    //decltype(fun) gg;  无法通过编译,是个重载函数        return 0;}
3.nullptr

The null pointer identifier, NULLPTR, is an identity that represents a null pointer, and is not an integer, which is the difference from a null macro that we commonly use. Null is just a macro defined as a constant integer 0, and nullptr is a keyword of c++11, a built-in identifier.

#include <iostream>#include <vector>using namespace std;void fun(int a){    cout << "call function: [int]\n" << endl;}void fun(int *a){    cout << "call function: [int*]\n" << endl;}int main(){    //C++11    fun(NULL);   //call function: [int]    fun(nullptr);  //call function: [int*]    int* p = NULL;    fun(p);  //call function: [int*]    return 0;}
4. Interval iteration range for

The syntax differences between c++98 and c++11 are as follows:

#include <iostream>#include <vector>using namespace std;int main(){    //C++98    vector<int> vec(8, 1);    cout << "C++98 range for:" << endl;    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)    {        cout << *it << endl;    }    //C++11    cout << "C++11 range for:" << endl;    for (auto d : vec)    {        cout << d << endl;    }    return 0;}

It is worth noting that the ability to use a range-based for loop must depend on some conditions. First, the scope of the For loop iteration is deterministic. For a class, if the class has a begin and End function, then For_each is the scope of the For loop iteration. For arrays, it is the range between the first and last element of the array. Second, the range-based for loop also requires an iterative object to implement operators such as + + and = =. There is no problem with containers in STL, such as String, array, map, and so on. Here is the practice of c++11 manipulating vectors and arrays:

#include <iostream> #include <vector>using namespace Std;int main () {vector<int> VEC (8, 1);    c++11 cout << "c++11 value range for:" << Endl;    /*d Non-reference, modify D does not affect the value in the vector */for (auto D:vec)//d stored in the VEC value {d = 2;    } for (auto D:vec) {cout << d << Endl;    } cout << "c++11 reference range for:" << Endl;    /* When the iteration variable d is a reference, the value in the vector can be modified */for (auto &d:vec) {d = 2;    } for (auto D:vec) {cout << d << Endl;    }//array for_each char arr[] = {' A ', ' B ', ' C ', ' d '};    for (auto &d:arr) {D-= 32;    } for (auto D:arr) {cout << d << Endl; }//traverse the two-dimensional array, note that the iteration variable row must be a reference.    If you want to use the range for method to traverse the higher-dimensional Array (Dim > 2), you only need to: except for the inner loop, all other outer loops are added ' & '.    int array2[5][5] = {0};    for (auto &row:array2) for (auto Col:row) cout << col << Endl; return 0;}
5. return type post syntax

Let's look at the following example, when the compiler infers Decltype (T1+T2) in the expression T1 and T2 are not declared, so the compilation fails.

#include <iostream>#include <vector>using namespace std;template<class T1, class T2>decltype(t1 + t2) sum(T1 t1, T2 t2){    return t1 + t2;}int main(){    auto total = sum(1, 2);    cout << total << endl;    return 0;}

So c++11 introduced the new syntax, that is, after moving the function's return value to the parameter declaration, the compound symbol->decltype (T1+T2) is called the trace return type. The original function return value is occupied by auto.

#include <iostream>#include <vector>using namespace std;template<class T1, class T2>auto sum(T1 t1, T2 t2) ->decltype(t1+t2){    return t1 + t2;}int main(){    auto total = sum(1, 2);    cout << total << endl;    return 0;}
6.final and override
struct B{    virtual void f1(int) const;    virtual void f2();    void f3();};struct D1 : public B{    void f1(int) const override;  //ok    void f2(int) override;   //error,B中没有形如f2(int)的函数    void f3() override;  //error,f3不是虚函数    void f4() override;  //error,B中无f4函数};struct D2 : public B{    void f1(int) const final;  //不许后续的其他类覆盖};struct D3 :public D2{    void f2();    void f1(int) const; //error,final函数不可覆盖};

Final can also be used to prevent inheritance from occurring

class NoDerived final{};class Bad :NoDerived   //NoDerived不可做基类{};class Base{};class Last final :Base{};class Bad2 :Last   //Last不可做基类{};
7.=default and =delete

For C + + classes, if a programmer does not define a special member function for it, the compiler implicitly automatically generates a default special member function, such as a copy constructor or a copy assignment operator, when a special member function is needed.

C++11 allows us to use =default to ask the compiler to generate a default constructor, and also allows us to use =delete to tell the compiler not to generate a default function for us

class B{    B() = default; //显示声明使用默认构造函数    B(const B&) = delete; //禁止使用类对象之间的拷贝    ~B() = default;  //显示声明使用默认析构函数    B& operator=(const B&) = delete;  //禁止使用类对象之间的赋值    B(int a);  };
8.LAMBDA-expression

In simple terms, a lambda function is a function (an anonymous function) whose syntax is defined as follows:

[capture](parameters) mutable ->return-type{statement}
    1. [=,&a,&b] means capturing variables A and b in the way of reference passing, capturing all other variables in a value-passing manner;
    2. [&,a,this] means that the this pointer of the variable A and class is captured in a value pass, and the reference is passed to catch all other variables.
#include <iostream>using namespace std;int main(){    auto f = []() {cout << "hello world!" << endl; };    f();  //hello world!    int a = 123;    auto f1 = [a] { cout << a << endl; };    f1();  //123    auto f2 = [&a] {cout << a << endl; };    a = 789;    f2();  //789    //隐式捕获:让编译器根据函数体中的代码来推断需要捕获哪些变量    auto f3 = [=] {cout << a << endl; };    f3();  //789    auto f4 = [&] {cout << a << endl; };    a = 990;    f4();  //990    auto f5 = [](int a, int b)->int {return a + b; };    printf("%d\n", f5(1, 2));  //3    return 0;}

Lambda expressions in C + + applications, sorting

#include <stdio.h>#include <algorithm>#include <vector>using namespace std;void print(char arr[], int len){    for (int i = 0; i < len; i++)    {        printf("%d ", arr[i]);    }    printf("\n");}bool cmp(char a, char b){    if (a > b)        return true;    else        return false;}int main(){    //c++98    char arr1[] = { 2,5,2,1,5,89,36,22,89 };    int len = sizeof(arr1) / sizeof(char);    sort(arr1, arr1 + len, cmp);    print(arr1, len);    //c++11    char arr2[] = { 2,5,2,1,5,89,36,22,89 };    int len2 = sizeof(arr2) / sizeof(char);    sort(arr2, arr2 + len2, [](char a, char b)->bool {return a > b; });    print(arr2, len2);    return 0;}
9.std::move

Std::move is designed for performance, and through std::move, unnecessary copy operations can be avoided. Std::move is the transfer of the State or ownership of an object from one object to another, except for a transfer, no memory relocation, or a memory copy.

#include <iostream>#include <utility>#include <vector>#include <string>int main(){    std::string str = "Hello";    std::vector<std::string> v;    //调用常规的拷贝构造函数,新建字符数组,拷贝数据    v.push_back(str);    std::cout << "After copy, str is \"" << str << "\"\n"; //After move, str is "Hello"    //调用移动构造函数,掏空str,掏空后,最好不要使用str    v.push_back(std::move(str));    std::cout << "After move, str is \"" << str << "\"\n";   //After move, str is ""    std::cout << "The contents of the vector are \"" << v[0]        << "\", \"" << v[1] << "\"\n";   //The contents of the vector are "Hello", "Hello"}
Second, STL new content 1.std::array
    1. With Std::array stored in the stack memory, we have the flexibility to access the elements in the heap in order to achieve higher performance, and because of the nature of the heap memory storage, there are times when we need to be responsible for releasing those resources.

    2. Using Std::array can make the code more modern and encapsulate some of the operation functions, while also being able to use the container algorithm in the standard library and so on, such as Std::sort.

Std::array will create a fixed-size array at compile time, std::array can not be implicitly converted to pointers, using Std::array is simple, just specify its type and size:

#include <stdio.h>#include <algorithm>#include <array>void foo(int* p){}int main(){    std::array<int, 4> arr = {4,3,1,2};    foo(&arr[0]);  //OK    foo(arr.data());  //OK    //foo(arr);  //wrong    std::sort(arr.begin(), arr.end());  //排序    return 0;}
2.std::forward_list

The std::forward_list is implemented using a one-way list, providing element insertion with O (1) complexity, no support for fast random access (which is also a feature of the list), and is the only container in the standard reservoir that does not provide a size () method. When bidirectional iterations are not required, there is a higher space utilization than the std::list.

#include <stdio.h>#include <algorithm>#include <iostream>#include <string>#include <forward_list>int main(){    std::forward_list<int> list1 = { 1, 2, 3, 4 };    //从前面向foo1容器中添加数据,注意不支持push_back    list1.pop_front();  //删除链表第一个元素    list1.remove(3);   //删除链表值为3的节点    list1.push_front(2);    list1.push_front(1);    list1.push_front(14);    list1.push_front(17);    list1.sort();    for (auto &n : list1)    {        if (n == 17)            n = 19;    }    for (const auto &n : list1)    {        std::cout << n << std::endl;  //1 2 2 4 14 19    }    return 0;}
3.std::unordered_map and Std::unordered_set

The elements in the unordered container are not sorted, internally through the Hash table, and the average complexity of the insertion and searching elements is O (constant), which can achieve significant performance gains without caring for the order of elements inside the container.

C++11 introduces two sets of unordered containers: Std::unordered_map/std::unordered_multimap and Std::unordered_set/std::unordered_multiset.

Here's how to use Unordered_map and unordered_set.

#include <stdio.h>#include <algorithm>#include <iostream>#include <string>#include <unordered_map>#include <unordered_set>void foo(int* p){}int main(){    //unordered_map usage    std::unordered_map<std::string, int> um = { {"2",2},{"1",1},{"3",3} };    //遍历    for (const auto &n : um)    {        std::cout << "key:" << n.first << "  value:" << n.second << std::endl;    }    std::cout << "value:" << um["1"] << std::endl;    //unordered_set usage    std::unordered_set<int> us = { 2,3,4,1};    //遍历    for (const auto &n : us)    {        std::cout << "value:" << n << std::endl;    }    std::cout << "value:" << us.count(9) << std::endl; //判断一个数是否在集合内,1存在0不存在    std::cout << "value:" << *us.find(1) << std::endl;  //查找一个特定的数是否在集合内,找到就返回该数的迭代器位置    return 0;}
Three, smart pointer 1. Std::shared_ptr

The

shared_ptr uses a reference count, and each copy of the shared_ptr points to the same memory. Every time he uses it, the internal reference count is added 1, each destructor is made, the internal reference count is reduced by 1, minus 0 o'clock, and the pointed heap memory is deleted. The reference count inside the shared_ptr is secure, but the read of the object needs to be locked.

#include <stdio.h>#include <memory>#include <iostream>int main(){    //auto ptr = std::make_shared<int>(10);    std::shared_ptr<int> ptr(new int(10));    std::shared_ptr<int> ptrC(ptr);    auto ptr2 = ptr;    {        auto ptr3 = ptr2;        std::cout << "pointer1.use_count() = " << ptr.use_count() << std::endl;  //4        std::cout << "pointer2.use_count() = " << ptr2.use_count() << std::endl;  //4    }    std::cout << "pointer1.use_count() = " << ptr.use_count() << std::endl;  //3    std::cout << "pointer2.use_count() = " << ptr2.use_count() << std::endl;  //3    int *p = ptr.get(); //获取原始指针    std::cout << "pointer1.use_count() = " << ptr.use_count() << std::endl;  //3    std::cout << "pointer2.use_count() = " << ptr2.use_count() << std::endl;  //3    return 0;}
3 2. Std::unique_ptr

Std::unique_ptr is an exclusive smart pointer that prohibits other smart pointers from sharing the same object, guaranteeing code security:

#include <stdio.h>#include <memory>#include <iostream>int main(){    std::unique_ptr<int> ptr(new int(10));    //auto ptr2 = ptr; //非法    //虽说unique_ptr是不可复制的,但我们可以使用std::move将其独占权转移到其他的unique_ptr    auto ptr2(std::move(ptr));    std::cout << *ptr2 << std::endl;    return 0;}
3. Std::weak_ptr

First look at the following code, if we are using shared_ptr in class father

father !son !

The above problem is the circular citation problem of shared_ptr. In order to avoid the circular reference problem of shared_ptr, we need to introduce a weak reference weak_ptr, weak_ptr is a kind of smart pointer introduced in order to cooperate with shared_ptr, the weak reference will not cause the reference count to increase, it is more like shared_ A helper of PTR rather than a smart pointer, because it does not behave as a normal pointer, does not overload operator* and->, and its greatest role is to assist the shared_ptr work, observing the use of resources like bystanders.

#include <iostream>#include <memory>using namespace std;class father;class son;class father {public:    father() {        cout << "father !" << endl;    }    ~father() {        cout << "~~~~~father !" << endl;    }    void setSon(shared_ptr<son> s) {        son = s;    }private:    //shared_ptr<son> son;    weak_ptr<son> son; // 用weak_ptr来替换};class son {public:    son() {        cout << "son !" << endl;    }    ~son() {        cout << "~~~~~~son !" << endl;    }    void setFather(shared_ptr<father> f) {        father = f;    }private:    shared_ptr<father> father;};void test() {    shared_ptr<father> f(new father());    shared_ptr<son> s(new son());    f->setSon(s);    s->setFather(f);}int main(){    test();    return 0;}

Output:

father !son !~~~~~~son !~~~~~father !

Learning c++11 new features based on c++98

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.