格式:
[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;
}
使用场景:
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();
}
decltype关键字用于获得对象或表达式的类型,如:
const vector<int> vi;
typedef decltype (vi.begin()) CIT;
CIT another_const_iterator;
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:
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.
示例
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
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
};
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.
“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;
}
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
}
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 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;
}
}
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
}
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
};
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';
}
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";
}
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);
}
An unordered container is a kind of hash table. C++11 offers four standard ones:
#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.