C++11新特性(持续更新)

1. Lambda表达式

格式:
[capture](parameters)->return-type {body}

#include 
#include 
#include 
 
int main()
{

   char s[]="Hello World!";

   int Uppercase = 0; //modified by the lambda

   std::for_each(s, s+sizeof(s), [&Uppercase] (char c) {

    if (isupper(c))

     Uppercase++;

    });
    
    std::cout<< Uppercase<<" uppercase letters in: "<< s<<std::endl;

}
  • The ampersand in [&Uppercase] means that the lambda body gets a reference to Uppercase so it can modify it. Without the ampersand, Uppercase would be passed by value.

2. Automatic Type Deduction and decltype

使用场景:

  • 类型复杂
  • 模板代码中
auto x=0; //x has type int because 0 is int
auto c='a'; //char

auto d=0.5; //double

auto national_debt=14400000000000LL;//long long
void func(const vector<int> &vi)
{
    auto ci=vi.begin();
}
  • auto关键字在C++11之前的语义是自动存储,C++11后废除了旧的语义

decltype关键字用于获得对象或表达式的类型,如:

const vector<int> vi;
typedef decltype (vi.begin()) CIT;

CIT another_const_iterator;

3. Uniform Initialization Syntax

C++11之前的初始化方法有:

  • 圆括号初始化,如
std::string s("hello");
int m=int(); //default initialization
  • =号初始化
std::string s="hello";
int x=5;
  • 对于一些数组和结构体,如
int arr[4]={0,1,2,3};
struct tm today={0};
  • 构造器初始化
struct S {
 int x;

 S(): x(0) {} };

C++11之后统一使用如下初始化方法:

class C
{

int a = 7; //C++11 only;

int b;

public:

 C(int i, int j);
 
 C()=default; //C++11

 virtual ~C() = default; //C++11
};

C c {0,0}; //C++11 only. Equivalent to: C c(0,0);

int* a = new int[3] { 1, 2, 0 }; /C++11 only

class X {

  int a[4];

public:

  X() : a{1,2,3,4} {} //C++11, member array initializer
  int func() = delete;
};

Defaulted functions have two advantages:

  • They are more efficient than manual implementations
  • and they rid the programmer from the chore of defining those functions manually
struct NoCopy
{

 NoCopy & operator =( const NoCopy & ) = delete;

 NoCopy ( const NoCopy & ) = delete;

};

NoCopy a;

NoCopy b(a); //compilation error, copy ctor is deleted

Deleted functions are useful for preventing object copying, among the rest. Recall that C++ automatically declares a copy constructor and an assignment operator for classes.

4. nullptr

示例

void f(int); //#1
void f(char *);//#2

//C++03

f(0); //which f is called?

//C++11

f(nullptr) //unambiguous, calls #2

nullptr is applicable to all pointer categories, including function pointers and pointers to members:

const char *pc=str.c_str(); //data pointers
if (pc!=nullptr)

  cout<<pc<<endl;

int (A::*pmf)()=nullptr; //pointer to member function

void (*pmf)()=nullptr; //pointer to function

5. Delegating Constructors

class M //C++11 delegating constructors
{

 int x, y;

 char *p;

public:

 M(int v) : x(v), y(0), p(new char [MAX]) {} //#1 target

 M(): M(0) {cout<<"delegating ctor"<<endl;} //#2 delegating

};

6. Rvalue References

An lvalue is an object that has a name, while an rvalue is an object that does not have a name (a temporary object).
The primary reason for adding rvalue references(specified with &&) is move semantics. Unlike traditional copying, moving means that a target object pilfers the resources of the source object, leaving the source in an “empty” state. In certain cases where making a copy of an object is both expensive and unnecessary, a move operation can be used instead. To appreciate the performance gains of move semantics, consider string swapping. A naive implementation would look like this:

void naiveswap(string &a, string & b)
{

 string temp = a;

 a=b;

 b=temp;

}

moving strings merely swaps two data members, without allocating memory, copying char arrays and deleting memory:

void moveswapstr(string& empty, string & filled)
{

//pseudo code, but you get the idea

 size_t sz=empty.size();

 const char *p= empty.data();

//move filled's resources to empty

 empty.setsize(filled.size());

 empty.setdata(filled.data());

//filled becomes empty

 filled.setsize(sz);

 filled.setdata(p);

}

If you’re implementing a class that supports moving, you can declare a move constructor and a move assignment operator like this:

class Movable
{

Movable (Movable&&); //move constructor

Movable&& operator=(Movable&&); //move assignment operator

};

The C++11 Standard Library uses move semantics extensively. Many algorithms and containers are now move-optimized.

7. Strongly-typed enums

“Traditional” enums in C++ export their enumerators in the surrounding scope, which can lead to name collisions, if two different enums in the same have scope define enumerators with the same name,

C++11 introduces the enum class keywords. They no longer export their enumerators in the surrounding scope. Moreover, we can also now inherit from an enum

#include 
using namespace std;

int main() {
    enum class Color { red, green = 20, blue };
    Color r = Color::blue;
    switch(r)
    {
        case Color::red  : std::cout << "red\n";   break;
        case Color::green: std::cout << "green\n"; break;
        case Color::blue : std::cout << "blue\n";  break;
    }
    
    // int n = r; // error: no scoped enum to int conversion
    int n = static_cast<int>(r); // OK, n = 21
    cout<<n<<endl;
}

8. Static Assert

C++11 introduces a new way to test assertions at compile-time, using the new keyword static_assert, this feature is very useful to add conditions to the template parameters.

#include 
 
template <class T>
void swap(T& a, T& b)
{
    static_assert(std::is_copy_constructible<T>::value,
                  "Swap requires copying");
    static_assert(std::is_nothrow_copy_constructible<T>::value
               && std::is_nothrow_copy_assignable<T>::value,
                  "Swap requires nothrow copy/assign");
    auto c = b;
    b = a;
    a = c;
}
 
template <class T>
struct data_structure
{
    static_assert(std::is_default_constructible<T>::value,
                  "Data Structure requires default-constructible elements");
};
 
struct no_copy
{
    no_copy ( const no_copy& ) = delete;
    no_copy () = default;
};
 
struct no_default
{
    no_default () = delete;
};
 
int main()
{
    int a, b;
    swap(a, b);
 
    no_copy nc_a, nc_b;
    swap(nc_a, nc_b); // 1
 
    data_structure<int> ds_ok;
    data_structure<no_default> ds_error; // 2
}

9.Variadic template

The variadic template is a template, which can take an arbitrary number of template arguments of any type. Both the classes & functions can be variadic.
C++11新特性(持续更新)_第1张图片

10. Range-based for loops

C++11 augmented the for statement to support the “foreach” paradigm of iterating over collections. it makes the code more simple and cleaner.

#include 
using namespace std;

int main() {
    int a[5] = {1,2,3,4,5};
    for(int b : a) {
        cout<<b<<endl;
    }
}

11. noexcept

If a function cannot throw an exception or if the program isn’t written to handle exceptions thrown by a function, that function can be declared noexcept.

// whether foo is declared noexcept depends on if the expression
// T() will throw any exceptions
template <class T>
  void foo() noexcept(noexcept(T())) {}
 
void bar() noexcept(true) {}
void baz() noexcept { throw 42; }  // noexcept is the same as noexcept(true)
 
int main() 
{
    foo<int>();  // noexcept(noexcept(int())) => noexcept(true), so this is fine
 
    bar();  // fine
    baz();  // compiles, but at runtime this calls std::terminate
}

12. Override Identifier

In C++03, it is possible to accidentally create a new virtual function, when one intended to override a base class function.

The override special identifier means that the compiler will check the base class(es) to see if there is a virtual function with this exact signature. And if there is not, the compiler will indicate an error.

struct A
{
    virtual void foo();
    void bar();
};
 
struct B : A
{
    void foo() const override; // Error: B::foo does not override A::foo
                               // (signature mismatch)
    void foo() override; // OK: B::foo overrides A::foo
    void bar() override; // Error: A::bar is not virtual
};

13. Threading Library

Unquestionably, the most important addition to C++11 from a programmer’s perspective is concurrency. C++11 has a thread class that represents an execution thread, promises and futures, which are objects that are used for synchronization in a concurrent environment, the async() function template for launching concurrent tasks, and the thread_local storage type for declaring thread-unique data. For a quick tour of the C++11 threading library, read Anthony Williams’ Simpler Multithreading in C++0x.

#include 
#include 
#include 
#include 
 
void f1(int n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 1 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}
 
void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}
 
class foo
{
public:
    void bar()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 3 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    int n = 0;
};
 
class baz
{
public:
    void operator()()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 4 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    int n = 0;
};
 
int main()
{
    int n = 0;
    foo f;
    baz b;
    std::thread t1; // t1 is not a thread
    std::thread t2(f1, n + 1); // pass by value
    std::thread t3(f2, std::ref(n)); // pass by reference
    std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
    std::thread t5(&foo::bar, &f); // t5 runs foo::bar() on object f
    std::thread t6(b); // t6 runs baz::operator() on object b
    t2.join();
    t4.join();
    t5.join();
    t6.join();
    std::cout << "Final value of n is " << n << '\n';
    std::cout << "Final value of foo::n is " << f.n << '\n';
}

14. New Smart Pointer Classes

C++98 defined only one smart pointer class, auto_ptr, which is now deprecated. C++11 includes new smart pointer classes: shared_ptr and the recently-added unique_ptr. Both are compatible with other Standard Library components, so you can safely store these smart pointers in standard containers and manipulate them with standard algorithms.

#include 
#include 
#include 
#include 
#include 
 
struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // Note: non-virtual destructor is OK here
    ~Base() { std::cout << "  Base::~Base()\n"; }
};
 
struct Derived: public Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }
};
 
void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // thread-safe, even though the
                                  // shared use_count is incremented
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}
 
int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();
 
    std::cout << "Created a shared Derived (as a pointer to Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    p.reset(); // release ownership from main
    std::cout << "Shared ownership between 3 threads and released\n"
              << "ownership from main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.join(); t2.join(); t3.join();
    std::cout << "All threads completed, the last one deleted Derived\n";
}

15. New C++ Algorithms

The C++11 Standard Library defines new algorithms that mimic the set theory operations all_of(), any_of() and none_of(). The following listing applies the predicate ispositive() to the range [first, first+n) and uses all_of(), any_of() and none_of() to examine the range’s properties:

#include 
#include 
#include 
#include 
#include 
using namespace std;

bool ispositive(int i) {
    return i > 0;
}

int main() {
    //C++11 code
    //are all of the elements positive?
    int first[5]={0,-12,34,50,80};
    cout<<all_of(first, first+4, ispositive)<<endl; //false
    
    //is there at least one positive element?
    cout<<any_of(first, first+4, ispositive)<<endl;//true
    
    // are none of the elements positive?
    cout<<none_of(first, first+4, ispositive)<<endl; //false
}

A new category of copy_n algorithms is also available. Using copy_n(), copying an array of 5 elements to another array is a cinch:

#include 
#include 
using namespace std;

int main() {
    int source[5]={0,12,34,50,80};
    int target[5];
    
    //copy 5 elements from source to target
    copy_n(source,5,target);
    auto print = [](const int& n) { std::cout << " " << n; };
    for_each(target, target+5, print);
}

The algorithm iota() creates a range of sequentially increasing values, as if by assigning an initial value to *first, then incrementing that value using prefix ++. In the following listing, iota() assigns the consecutive values {10,11,12,13,14} to the array arr, and {‘a’, ‘b’, ‘c’} to the char array c.

#include 
#include 
using namespace std;

int main() {
    int a[5]={0};
    char c[3]={0};
    
    iota(a, a+5, 10); //changes a to {10,11,12,13,14}
    iota(c, c+3, 'a'); //{'a','b','c'}
    
    //auto print = [](const int& n) { std::cout << " " << n; };
    auto printInt = [](int &n) { cout << " " << n; };
    auto printChar = [](char &n) { cout << " " << n; };
    for_each(a, a+5, printInt);
    cout<<endl;
    for_each(c, c+3, printChar);
}

16. Unordered containers

An unordered container is a kind of hash table. C++11 offers four standard ones:

  • unordered_map
  • unordered_set
  • unordered_multimap
  • unordered_multiset
#include 
#include 
#include 
 
int main()
{
    // Create an unordered_map of three strings (that map to strings)
    std::unordered_map<std::string, std::string> u = {
        {"RED","#FF0000"},
        {"GREEN","#00FF00"},
        {"BLUE","#0000FF"}
    };
 
    // Iterate and print keys and values of unordered_map
    for( const auto& n : u ) {
        std::cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n";
    }
 
    // Add two new entries to the unordered_map
    u["BLACK"] = "#000000";
    u["WHITE"] = "#FFFFFF";
 
    // Output values by key
    std::cout << "The HEX of color RED is:[" << u["RED"] << "]\n";
    std::cout << "The HEX of color BLACK is:[" << u["BLACK"] << "]\n";
 
    return 0;
}

C++11 still lacks a few useful libraries such as an XML API, sockets, GUI, reflection — and yes, a proper automated garbage collector. However, it does offer plenty of new features that will make C++ more secure, efficient (yes, even more efficient than it has been thus far! See Google’s benchmark tests), and easier to learn and use.

Reference

  1. https://smartbear.com/blog/develop/the-biggest-changes-in-c11-and-why-you-should-care/
  2. https://en.cppreference.com/w/cpp/algorithm/for_each
  3. https://cppdepend.com/blog/?p=319
  4. C++帮助文档. https://en.cppreference.com/w/
  5. C++在线运行工具. http://cpp.sh/

你可能感兴趣的:(C/C++)