1.自动类型推导
在定义变量时,必须先给出变量的实际类型,编译器才允许定义,但有些情况下可能不知道需要实际类型怎 么给,或者类型写起来特别复杂,C++11中,可以使用auto来根据变量初始化表达式类型推导变量的实际类型,可以给程序的书写提供许多方 便。将程序中c与it的类型换成auto,程序可以通过编译,而且更加简洁。
void test01()
{
map<string, string>ssmap;
auto it = ssmap.begin();
}
2.列表初始化
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定 义的类型,使用初始化列表时,可添加等号(=),也可不添加。
void test02()
{
int arr[] = { 1,2,3,4,5 };
vector<int>iv={ 1,2,3,4,5 };//c11初始化方法
vector<int>iv1{ 1,2,3,4,5 };
}
void test03()
{
int* p = new int[10]{ 1,2,3,4,5,6,7,8,9,10 };
}
class Point
{
public:
Point(int x = 0, int y = 0) : _x(x), _y(y)
{}
private:
int _x;
int _y;
};
void test04()
{
Point p{ 1, 2 };//标准库支持单个对象的列表初始化
}
template<class Type>
class SeqList
{
public:
SeqList(const initializer_list<Type>& list)
:capacity(list.size()), size(0)
{
base = new Type[capacity];
for (const auto& e : list)
base[size++] = e;
}
private:
Type* base;
size_t capacity;
size_t size;
};
void test05()
{
SeqList<int>sq = { 1,2,3,4,5 };
}
3.decltype类型推导
auto使用的前提是:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型。但有 时候可能需要根据表达式运行完成之后结果的类型进行推导,因为编译期间,代码不会运行,此时auto也就 无能为力。
template<class T1, class T2>
T1 Add(const T1& left, const T2& right)
{
return left + right;
}
int main()
{
int a = 10;
int b = 20;
// 用decltype推演a+b的实际类型,作为定义c的类型
decltype(a+b) c;
cout<<typeid(c).name()<<endl;
return 0;
}
void test06()
{
map<int, string>::iterator pos;
cout << typeid(pos).name() << endl;
auto pos1 = pos;
decltype(pos) it;
int a = 10;
int b = 20;
decltype(a) c;//省去了初始化步骤,萃取a的类型
}
void* GetMemory(size_t size)
{
return malloc(size);
}
int main()
{
// 如果没有带参数,推导函数的类型
cout << typeid(decltype(GetMemory)).name() << endl;
// 如果带参数列表,推导的是函数返回值的类型,注意:此处只是推演,不会执行函数
cout << typeid(decltype(GetMemory(0))).name() <<endl;
return 0;
}
4.默认成员函数控制
在C++中对于空类编译器会生成一些默认的成员函数,比如:构造函数、拷贝构造函数、运算符重载、析构 函数和&和const&的重载、移动构造、移动拷贝构造等函数。如果在类中显式定义了,编译器将不会重新生 成默认版本。有时候这样的规则可能被忘记,最常见的是声明了带参数的构造函数,必要时则需要定义不带 参数的版本以实例化无参的对象。而且有时编译器会生成,有时又不生成,容易造成混乱,于是C++11让程 序员可以控制是否需要编译器生成。
#include<iostream>
using namespace std;
//单例模式不是
class Test
{
public:
Test(int d):m_a(d) {}
Test(const Test&) = delete;
Test& operator=(const Test&) = delete;
private:
//Test(const Test&);
int m_a;
};
void test01()
{
Test t(10);
//Test t1(t);
Test t2(20);
Test te(30);
}
void main()
{
test01();
system("pause");
}
class A
{
public:
A(int a) : _a(a)
{}
// 显式缺省构造函数,由编译器生成
//A() = default;//相当于A(){}
A() = delete;
A(const A&) = default;//占位符?
// 在类中声明,在类外定义时让编译器生 成默认赋值运算符重载
A& operator=(const A& a);
private:
int _a;
};
A& A::operator=(const A& a) = default;
void test07()
{
A a1(10);
//A a2;
A a3(a1);
//a2 = a1;
}
class B
{
public:
B(int a) :_a(a) {}
B(const B& a) = delete;//一个类不能拷贝构造
private:
//B(const A& a) { this->_a = a._a; }//一个类不能拷贝构造
int _a;
};
void test08()
{
B b(1);
//B b1(b);//不能拷贝构造
}
void test09()
{
int x = 10;
int& b = x;
const int& a = 10;//常量用常引用
int&& a = 10;//对于右值的引用
}
#include<iostream>
using namespace std;
void test01()
{
int a = 10;
const int& b = a;
a = 100;
//int&& c = a;//右值引用只能引用右值
const int& d = 10;
int&& e = 10;
}
int fun(int a, int b)
{
int value = a + b;
return value;//无名临时空间具有常性
}
void test02()
{
int&& ret = fun(10,20);
const int& ret1 = fun(10, 20);
cout << ret << endl;
/* cout << ret << endl;
cout << ret << endl;*/
}
void main()
{
test02();
system("pause");
}
int main()
{
// 普通类型引用只能引用左值,不能引用右值
int a = 10;
int& ra1 = a; // ra为a的别名
//int& ra2 = 10; // 编译失败,因为10是右值
const int& ra3 = 10;
const int& ra4 = a;
return 0;
}
int fun(int a, int b)
{
static int value = a + b;
return value;
}
void test10()
{
const int& ret = fun(10, 20);
int&& ret = fun(10, 20);
}
void test11()
{
int a = 10;
//int&& b = a;//右值引用只能引用右值
}
6.移动语义
为了解决:浅拷贝+对象按值返回会造成空间浪费
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class String
{
public:
String(const char* str = "")
{
if (nullptr == str)
str = "";
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
String(const String& s)
: _str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}
//右值引用 的拷贝构造函数 实现移动语义
String(String&& s)
: _str(s._str)
{
s._str = nullptr;
}
String& operator=(const String& s)
{
if (this != &s)
{
//异常安全
char* pTemp = new char[strlen(s._str) + 1];
strcpy(pTemp, s._str);
delete[] _str;
_str = pTemp;
}
return *this;
}
String operator+(const String& s)
{
char* pTemp = new char[strlen(_str) + strlen(s._str) + 1];
strcpy(pTemp, _str);
strcpy(pTemp + strlen(_str), s._str);
String strRet(pTemp);
return strRet;
}
~String()
{
if (_str) delete[] _str;
}
private:
char* _str;
};
void test01()
{
String s1("hello");
//String s2 = s1;//不能使用移动语义,s1不是右值
String s2 = move(s1);//move将s1强转为右值,可以调用移动语义拷贝构造 s1被搬空
}
void test02()
{
String s1("hello");
String s2("world");
String s3(s1 + s2);
}
void test03()
{
String s1("hello world");
String s2(move(s1));//s1被搬空
String s3(s2);
}
int main()
{
test03();
return 0;
}
移动语义例子:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class String
{
public:
String(const char* str = "")
{
if (nullptr == str)
str = "";
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
String(String&& s)
: _str(s._str)
{
s._str = nullptr;
}
String(const String& s)
: _str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}
String& operator=(const String& s)
{
if (this != &s)
{
char* pTemp = new char[strlen(s._str) + 1];
strcpy(pTemp, s._str);
delete[] _str;
_str = pTemp;
}
return *this;
}
String operator+(const String& s)
{
char* pTemp = new char[strlen(_str) + strlen(s._str) + 1];
strcpy(pTemp, _str);
strcpy(pTemp + strlen(_str), s._str);
String strRet(pTemp);
return strRet;
}
~String()
{
if (_str) delete[] _str;
}
private:
char* _str;
};
class Person
{
public:
Person(const char* name, const char* sex, int age)
: _name(name)
, _sex(sex)
, _age(age)
{}
Person(const Person& p)
: _name(p._name)
, _sex(p._sex)
, _age(p._age)
{}
#if 0
Person(Person&& p)
: _name(p._name)
, _sex(p._sex)
, _age(p._age)
{}
#else//调用String 类的移动语义
Person(Person&& p)
: _name(move(p._name))
, _sex(move(p._sex))
, _age(p._age)
{}
#endif
private:
String _name;
String _sex;
int _age;
};
Person GetTempPerson()
{
Person p("prety", "male", 18);
return p;
}
int main()
{
Person p(GetTempPerson());
return 0;
}
int main()
{
String s1("hello world");
String s2(move(s1));
String s3(s2);
return 0;
}
9.完美转发
#include<iostream>
using namespace std;
void Fun(int& x) { cout << "lvalue ref" << endl; }
void Fun(int&& x) { cout << "rvalue ref" << endl; }
void Fun(const int& x) { cout << "const lvalue ref" << endl; }
void Fun(const int&& x) { cout << "const rvalue ref" << endl; }
template<typename T>
void PerfectForward(T&& t)
{
Fun(forward<T>(t));//对t进行完美转发
//Fun(std::forward<T>(t));
}
void test01()
{
int a = 10;
PerfectForward(a);
PerfectForward(10);
const int b = 20;
PerfectForward(b);
}
int main()
{
test01();
return 0;
}
10lambda表达式的存在意义:提供一个匿名的函数对象(仿函数),不用整个给出类的定义,比较简便。
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
void test01()
{
int array[] = { 4,1,8,5,3,7,0,9,2,6 };
int n = sizeof(array) / sizeof(array[0]);
// 默认按照小于比较,排出来结果是升序
sort(array, array + sizeof(array) / sizeof(array[0]));
//qsort();
for (int i = 0; i < n; ++i)
cout << array[i] <<" ";
cout << endl;
// 如果需要降序,需要改变元素的比较规则
sort(array, array + sizeof(array) / sizeof(array[0]), greater<int>());
for (int i = 0; i < n; ++i)
cout << array[i] <<" ";
}
struct Goods
{
string _name;
double _price;
};
struct Goods_Less
{
bool operator()(const struct Goods& g1, const struct Goods& g2)
{
return g1._price < g2._price;
}
};
struct Goods_Greater
{
bool operator()(const struct Goods& g1, const struct Goods& g2)
{
return g1._price > g2._price;
}
};
int main()
{
Goods gds[] = { { "苹果", 2.1 }, { "相交", 3 }, { "橙子", 2.2 }, {"菠萝", 1.5} };
int n = sizeof(gds) / sizeof(gds[0]);
//sort(gds, gds + n, Goods_Greater());//谓词这里传函数指针或者仿函数都可以
sort(gds, gds + n, [](const struct Goods& g1,
const struct Goods& g2)->bool
{return g1._price > g2._price; });//lambda表达式就是一个无名的仿函数对象,底层就是仿函数对象实现的
return 0;
}
示例:
#include<iostream>
using namespace std;
void test01()//lambda表达式就是用在函数对象(谓词)那里使用的,省略了类的给出)
{
[]()->void {};//最基本的lanbda //匿名函数对象
//[]捕获块
//()参数列表
//->返回值
//{}函数体
}
void test02()
{
auto f1 = [](int a, int b)->int {return a + b; };
cout << f1(10, 20) << endl;
cout << typeid(f1).name() << endl;
}
void test03()
{
auto f1 = []{cout << "hello lambda" << endl; };//没有参数可省略(),没有返回值->可省略
f1();
}
void main()
{
test03();
system("pause");
}
#include<iostream>
using namespace std;
int a = 1;
int b = 2;
int fun()
{
return a + b;
}
void test01()
{
cout << fun() << endl;
int x = 10;
int y = 20;
auto f1 = [x,y/*,d*/] {cout << a + b+x+y << endl; };//局部变量需要捕获 lambda前面是父作用域,后面是子作用域,一般对父作用域进行捕获
int d = 30;
f1();
}
void test02()
{
int x = 10;
int y = 20;
auto f1 = [=](int p, int q)mutable->int//实参不会改变,仅在函数内部改变形参 mutable不可以省略
auto f1 = [&](int p, int q)->int//实参会改变
{
p = 100;
q = 200;
x = 300;
y = 500;
return p + q + x + y;
};
cout << f1(10,20) << endl;
cout << "x=" << x << " y=" << y << endl;
}
class Test
{
public:
int fun(int x, int y)
{
auto f=[this](int x, int y)->int
{
return x + y + m_a + m_b;
};
return f(x,y);
}
private:
int m_a=1;
int m_b = 2;
};
void test03()
{
Test t;
cout << t.fun(10, 20) << endl;
}
void main()
{
test03();
system("pause");
}
C11线程库操作:
#include<thread>
#include<iostream>
using namespace std;
struct Test
{
int a;
double b;
char c;
};
struct Student
{
char name[10];
int age;
};
struct Data
{
int data;
Test test_data;
Student student_data;
};
//多线程程序
void thread_fun(Data* pdt)
{
for (int i = 0; i < pdt->data; ++i)
{
cout << "This is Child Thread." << endl;
}
cout << pdt->student_data.name << endl;
cout << pdt->student_data.age << endl;
};
void test01()
{
int n = 5;
Test t={ 10,12.34,'A' };
Student s = { "hym",18 };
Data dt = { n,t,s };
thread td(thread_fun,&dt);
//cout << td.get_id() << endl;
for (int i = 0; i < 10; ++i)
{
cout << "This is Main Thread." << endl;
}
//td.detach();
td.join();
}
void main()
{
test01();
system("pause");
}
#include<iostream>
#include<thread>
using namespace std;
class Test
{
public:
void fun()
{
cout << "class Test.fun()" << endl;
}
int m_a;
};
struct Threadobj
{
void operator()()
{
cout << "Hello Threadobj" << endl;
}
};
void thread_fun()
{
cout << "thread id" << this_thread::get_id() << endl;
}
void thread_fun1(int& a)
{
a += 10;
cout << "int fun a="<<a << endl;
}
void thread_fun2(int* a)
{
*a += 10;
cout << "int fun *a=" << *a << endl;
}
void thread_fun4(int a)
{
a += 10;
}
void thread_fun3(Test* t)
{
t->fun();
}
void test01()
{
cout << "Main thread id" << this_thread::get_id() << endl;
thread th(thread_fun);
cout << "Child id" << th.get_id() << endl;
th.join();
}
void test02()
{
thread th[10];
/*for (int i = 0; i < 10; ++i)
th[i](thread_fun1);*/
}
void test03()
{
cout << "Main thread id" << this_thread::get_id() << endl;
thread th(thread_fun);
cout << "thread id" << th.get_id() << endl;
th.detach();
cout << "thread id" << th.get_id() << endl;
}
void test04()
{
thread th;
thread::id id = th.get_id();
cout << "id=" << id << endl;
}
void test05()
{
thread th(thread_fun);//函数指针
th.join();
thread th1([] {cout << "hello lambda thread" << endl; });//lambda表达式
th1.join();
Threadobj thobj;
thread th2(thobj);
//thread th2(Threadobj());//不能创建线程 临时对象不行 必须先创建出对象再放进来
th2.join();
}
void test06()
{
thread th(thread_fun);
//thread th1 = th;//不能拷贝构造
thread th1 = move(th);
}
void test07()
{
//thread th;
thread th(thread_fun);
th.detach();
if (th.joinable())
{
cout << "th join able." << endl;
}
else
{
cout << "th join unable" << endl;
}
//th.join();
}
//void test08()//传值不能改变实参
//{
// int a = 10;
// thread th(thread_fun1, a);
// th.join();
// cout << "int test08 a=" << a << endl;
//}
void test09()
{
int a = 10;
thread th(thread_fun2, &a);//传地址
th.join();
cout << "int test08 a=" << a << endl;
}
void test10()
{
int a = 10;
thread th(thread_fun1, ref(a));//传引用
th.join();
cout << "int test08 a=" << a << endl;
}
void test11()//仅传成员变量不需要传this指针
{
Test t;
thread th(thread_fun4,t.m_a);
th.join();
}
void test12()//传对象的成员函数需要传this指针
{
Test t;
thread th(&Test::fun,&t);//使t对象调用fun函数 不加&也可以
th.join();
}
void main()
{
test12();
system("pause");
}
#include<iostream>
#include<thread>
using namespace std;
// jion()的误用一
void ThreadFunc() { cout << "ThreadFunc()" << endl; }
bool DoSomething() { return false; }
int main()
{
std::thread t(ThreadFunc);
if (!DoSomething())
return -1;
t.join();
return 0;
}
#include<iostream>
#include<thread>
using namespace std;
void ThreadFunc() { cout << "ThreadFunc()" << endl; }
void Test1() { throw 1; }
void Test2()
{
int* p = new int[10];
std::thread t(ThreadFunc);
try
{
Test1();
}
catch (...)
{
delete[] p;
throw;
}
//t.jion();//执行不到
}
以上两段代码中join的调用位置不对,导致线程资源无法正常回收。采用jion()方式结束线程时,jion()的调用位置非常关键。为了避免该问题,可以采用RAII的方式 对线程对象进行封装,比如:
#include<iostream>
#include<thread>
using namespace std;
class mythread
{
public:
explicit mythread(std::thread& t) :m_t(t) {}
~mythread()
{
if (m_t.joinable())
m_t.join();
}
mythread(mythread const&) = delete;
mythread& operator=(const mythread&) = delete;
private:
std::thread& m_t;
};
void ThreadFunc() { cout << "ThreadFunc()" << endl; }
bool DoSomething() { return false; }
int main()
{
thread t(ThreadFunc);
mythread q(t);
if (DoSomething())
return -1;
//t.join();
return 0;
}
detech例子:
#include<iostream>
#include<thread>
using namespace std;
void thread_fun()
{
for(;;)
cout << "thread_fun()" << endl;
}
void test01()
{
thread th(thread_fun);
th.detach();
//th.join();
}
void main()
{
test01();
system("pause");
}
按数组创建线程:
#include<iostream>
#include<thread>
using namespace std;
void thread_fun()
{
cout << "thread_fun" <<endl;
}
void test01()
{
/*thread th1(thread_fun);
thread th2(thread_fun);
thread th3(thread_fun);
th1.join();
th2.join();
th3.join();*/
thread* thar[3];
for (int i = 0; i < 3; ++i)
{
thar[i] = new thread(thread_fun);
}
for (int i = 0; i < 3; ++i)
thar[i]->join();
}
void main()
{
test01();
system("pause");
}
线程安全:
#include <iostream>
#include<mutex>
using namespace std;
#include <thread>
//多线程 临界(共享资源) 创建线程的目的是并发性,效率高
unsigned long sum = 0L;
mutex t;
void fun(size_t num)
{
for (size_t i = 0; i < num; ++i)
{
t.lock();
sum++;
t.unlock();
}
}
int main()
{
cout << "Before joining,sum = " << sum << std::endl;
thread t1(fun, 10000000);
thread t2(fun, 10000000);
t1.join();
t2.join();
cout << "After joining,sum = " << sum << std::endl;
return 0;
}
使用原子操作可以解决:
#include <iostream>
using namespace std;
#include <thread>
#include <atomic>
atomic_long sum={0};//初始化列表
void fun(size_t num)
{
for (size_t i = 0; i < num; ++i)
{
sum++; // 原子操作
//printf("sum=%d\n", sum);
//cout << "sum=" << sum << endl;
}
}
int main()
{
cout << "Before joining, sum = " << sum << std::endl;
thread t1(fun, 1000000);
thread t2(fun, 1000000);
t1.join();
t2.join();
cout << "After joining, sum = " << sum << std::endl;
return 0;
}
#include<iostream>
using namespace std;
#include <thread>
#include <mutex>
int number = 0;
mutex g_lock;
int ThreadProc1()
{
for (int i = 0; i < 1000000; i++)
{
//g_lock.lock();
//lock_guard<mutex> lock(g_lock);
unique_lock<mutex> lock(g_lock);
++number;
//cout << "thread 1[] :" << number << endl;
//printf("thread 1[%d] :%d\n", i, number);
//g_lock.unlock();
}
return 0;
}
int ThreadProc2()
{
for (int i = 0; i < 1000000; i++)
{
//g_lock.lock();
//lock_guard<mutex> lock(g_lock);
unique_lock<mutex> lock(g_lock);
--number;
//cout << "thread 2 :" << number << endl;
//printf("thread 2[%d] :%d\n", i, number);
//g_lock.unlock();
}
return 0;
}
int main()
{
thread t1(ThreadProc1);
thread t2(ThreadProc2);
t1.join();
t2.join();
cout << "number:" << number << endl;
system("pause");
return 0;
}
#include<iostream>
using namespace std;
template<class _Mutex>
class lock_guard
{
public:
// 在构造lock_gard时,_Mtx还没有被上锁
explicit lock_guard(_Mutex& _Mtx)
: _MyMutex(_Mtx)
{
_MyMutex.lock();
}
// 在构造lock_gard时,_Mtx已经被上锁,此处不需要再上锁
lock_guard(_Mutex& _Mtx, adopt_lock_t)
: _MyMutex(_Mtx)
{}
~lock_guard() _NOEXCEPT
{
_MyMutex.unlock();
}
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
private:
_Mutex& _MyMutex;
};