// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
//1.关键字auto
//auto并没有让C++成为弱类型语言,也没有弱化变量什么,只是使用auto的时候,编译器根据上下文情况,确定auto变量的真正类型。
/*
auto AddTest(int a, int b)
{
return a + b;
}
int main()
{
auto index = 10;
auto str = "abc";
auto ret = AddTest(2, 4);
std::cout << "index:" << index << std::endl;
std::cout << "str: " << str << std::endl;
std::cout << "ret:" << ret << std::endl;
system("pause");
return 0;
}
*/
//2.关键字nullptr
//NULL在c++里表示空指针,看到问题了吧,我们调用test.TestWork(NULL),其实期望是调用的是void TestWork(int * index),
//但结果调用了void TestWork(int index)。但使用nullptr的时候,我们能调用到正确的函数。
/*
class Test
{
public:
void TestWork(int index)
{
std::cout << "TestWork1" << std::endl;
}
void TestWork(int* index)
{
std::cout << "TestWork2" << std::endl;
}
};
int main()
{
Test test;
test.TestWork(NULL);
test.TestWork(nullptr);
system("pause");
}
*/
//3.for循环语法,STL容器都同样适用
/*
int main()
{
int numbers[] = { 1,2,3,4,5 };
std::cout << "numbers:" << std::endl;
for (int num : numbers)
{
std::cout << num << std::endl;
}
system("pause");
return 0;
}
*/
//4.STL容器之std::array
/*
#include <array>
int main()
{
std::array<int, 4> arrayDemo = { 1,2,3,4 };
std::cout << "arrayDemo:" << std::endl;
for (auto atr : arrayDemo)
{
std::cout << atr << std::endl;
}
int arrayDemoSize = arrayDemo.size();
std::cout << "arrayDemo size:" << arrayDemoSize << std::endl;
system("pause");
return 0;
}
*/
//5.std::forward_list
//std::forward_list为从++新增的线性表,与list区别在于它是单向链表。
/*
#include <forward_list>
int main()
{
std::forward_list<int> numbers = { 1,2,3,4,5,4,4 };
std::cout << "numbers:" << std::endl;
for (auto num : numbers)
{
std::cout << num << std::endl;
}
numbers.remove(4);
std::cout << "numbers after remove:" << std::endl;
for (auto num : numbers)
{
std::cout << num << std::endl;
}
system("pause");
return 0;
}
*/
//6.std::unordered_map
//std::unordered_map与std::map用法基本差不多,但STL在内部实现上有很大不同,std::map使用的数据结构为二叉树,
//而std::unordered_map内部是哈希表的实现方式,哈希map理论上查找效率为O(1)。但在存储效率上,哈希map需要增加哈希表的内存开销。
/*
#include <string>
#include <unordered_map>
int main()
{
std::unordered_map<std::string , std::string> mymap =
{
{"house", "maison"},
{"apple", "pomme"},
{"tree", "arbre"},
{"book", "livre"},
{"door", "porte"},
{"grapefruit", "pamplemousse"}
};
unsigned n = mymap.bucket_count();
std::cout << "mymap has " << n <<" bukets."<< std::endl;
for (unsigned i = 0; i < n; i++)
{
std::cout << "buket #" << i << " contains:";
for (auto it = mymap.begin(i); it != mymap.end(i); ++it)
{
std::cout << "[" << it->first << ":" << it->second << "] ";
}
std::cout << std::endl;
}
auto iter = mymap.find("tree");
std::cout << "tree: " << iter->second << std::endl;
system("pause");
return 0;
}
*/
//7.std::unordered_set
//std::unordered_set的数据存储结构也是哈希表的方式结构,除此之外,std::unordered_set在插入时不会自动排序,这都是std::set表现不同的地方。
/*
#include <iostream>
#include <string>
#include <unordered_set>
#include <set>
int main()
{
std::unordered_set<int> unorder_set;
unorder_set.insert(7);
unorder_set.insert(5);
unorder_set.insert(3);
unorder_set.insert(4);
unorder_set.insert(6);
std::cout << "unorder_set:" << std::endl;
for (auto itor : unorder_set)
{
std::cout << itor << std::endl;
}
std::set<int> set;
set.insert(7);
set.insert(5);
set.insert(3);
set.insert(4);
set.insert(6);
std::cout << "set:" << std::endl;
for (auto itor : set)
{
std::cout << itor << std::endl;
}
system("pause");
return 0;
}
*/
//8.多线程
//std::thread
//std::thread为C++11的线程类,使用方法和boost接口一样,非常方便,同时,C++11的std::thread解决了boost::thread中构成参数限制的问题,
//我想着都是得益于C++11的可变参数的设计风格。
/*
#include <iostream>
#include <thread>
void threadfun1()
{
std::cout << "threadfun1 -1\r\n" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "threadfun1 -2" << std::endl;
}
void threadfun2(int iParam, std::string sParam)
{
std::cout << "threadfun2 -1" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "threadfun2 -2" << std::endl;
}
int main()
{
std::thread t1(threadfun1);
t1.join();
std::cout << "join" << std::endl;
std::thread t2(threadfun2, 10, "abc");
t2.detach();
std::cout << "detach" << std::endl;
system("pause");
return 0;
}
*/
//thread构造之后就会立即执行
//有以上输出结果可以得知,t1.join()会等待t1线程退出后才继续往下执行,t2.detach()为异步方式,
//detach字符输出后,主函数退出,threadfun2还未执行完成,但是在主线程退出后,t2的线程也被已经被强退出。
//9.std::atomic
//std::atomic为C++11分装的原子数据类型。
//什么是原子数据类型?
//从功能上看,简单地说,原子数据类型不会发生数据竞争,能直接用在多线程中而不必我们用户对其进行添加互斥资源锁的类型。从实现上,大家可以理解为这些原子类型内部自己加了锁。
//我们下面通过一个测试例子说明原子类型std::atomic_int的特点。
//下面例子中,我们使用10个线程,把std::atomic_int类型的变量iCount从100减到1。
/*
#include <iostream>
#include <list>
#include <thread>
#include <atomic>
#include <stdio.h>
std::atomic_bool bIsReady = false;
std::atomic_int iCount = 100;
void threadfun1()
{
if (!bIsReady)
{
std::this_thread::yield();
}
while (iCount > 0)
{
printf("iCount:%d\r\n", iCount--);
}
}
int main()
{
std::atomic_bool b;
std::list<std::thread> lstThread;
for (int i = 0; i < 10; i++)
{
lstThread.push_back(std::thread(threadfun1));
}
for (auto& th : lstThread)
{
th.join();
}
system("pause");
return 0;
}
*/
//10.std::condition_variable
// C++11中的std::condition_variable就像Linux下使用pthread_cond_wait和pthread_cond_signal一样,可以让线程休眠,
//直到被唤醒,现在在从新执行。线程等待在多线程编程中使用非常频繁,经常需要等待一些异步执行的条件的返回结果。
/*
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id)
{
std::unique_lock<std::mutex> lck(mtx);
while (!ready)
{
cv.wait(lck);
}
std::cout << "thread " << id << '\n';
}
void go()
{
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
}
int main()
{
std::thread threads[10];
for (int i = 0; i < 10; i++)
{
threads[i] = std::thread(print_id, i);
}
std::cout << "10 threads ready to race...\n";
go();
for (auto& th : threads)
th.join();
system("pause");
return 0;
}
*/
//上面的代码,在14行中调用cv.wait(lck)的时候,线程将进入休眠,在调用33行的go函数之前,10个线程都处于休眠状态,
//当22行的cv.notify_all()运行后,14行的休眠将结束,继续往下运行,最终输出如上结果。
//11.智能指针内存管理
//std::shared_ptr包装了new操作符动态分别的内存,可以自由拷贝复制,基本上是使用最多的一个智能指针类型。
//#include <memory>
//#include <iostream>
//class Test
//{
//public:
// Test()
// {
// std::cout << "Test()" << std::endl;
// }
// ~Test()
// {
// std::cout << "~Test()" << std::endl;
// }
//};
//
//int main()
//{
// std::shared_ptr<Test> p1 = std::make_shared<Test>();
// std::cout << "1 ref:" << p1.use_count() << std::endl;
// {
// std::shared_ptr<Test> p2 = p1;
// std::cout << "2 ref:" << p1.use_count() << std::endl;
// }
// std::cout << "3 ref:" << p1.use_count() << std::endl;
// system("pause");
// return 0;
//}
//1、std::make_shared封装了new方法,boost::make_shared之前的原则是既然释放资源delete由智能指针负责,那么应该把new封装起来,
//否则会让人觉得自己调用了new,但没有调用delete,似乎与谁申请,谁释放的原则不符。C++也沿用了这一做法。
//2、随着引用对象的增加std::shared_ptr<Test> p2 = p1,指针的引用计数有1变为2,当p2退出作用域后,p1的引用计数变回1,
//当main函数退出后,p1离开main函数的作用域,此时p1被销毁,当p1销毁时,检测到引用计数已经为1,就会在p1的析构函数中调用delete之前std::make_shared创建的指针。
//12.std::weak_ptr
//std::weak_ptr网上很多人说其实是为了解决std::shared_ptr在相互引用的情况下出现的问题而存在的,C++官网对这个只能指针的解释也不多,
//那就先甭管那么多了,让我们暂时完全接受这个观点。
//std::weak_ptr有什么特点呢?与std::shared_ptr最大的差别是在赋值是,不会引起智能指针计数增加。
//#include <iostream>
//#include <memory>
//class TestB;
//class TestA
//{
//public:
// TestA()
// {
// std::cout << "TestA()" << std::endl;
// }
// void ReferTestB(std::shared_ptr<TestB> test_ptr)
// {
// m_TestB_Ptr = test_ptr;
// }
// ~TestA()
// {
// std::cout << "~TestA()" << std::endl;
// }
//private:
// std::shared_ptr<TestB> m_TestB_Ptr;//TestB的智能指针
//};
//class TestB
//{
//public:
// TestB()
// {
// std::cout << "TestB()" << std::endl;
// }
// void ReferTestA(std::shared_ptr<TestA> test_ptr)
// {
// m_TestA_Ptr = test_ptr;
// }
// ~TestB()
// {
// std::cout << "~TestB()" << std::endl;
// }
//private:
// std::shared_ptr<TestA> m_TestA_Ptr;//TestB的智能指针
//};
//int main()
//{
// std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
// std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
// ptr_a->ReferTestB(ptr_b);
// ptr_b->ReferTestA(ptr_a);
// return 0;
//}
//大家可以看到,上面代码中,我们创建了一个TestA和一个TestB的对象,但在整个main函数都运行完后,都没看到两个对象被析构
//#include <iostream>
//#include <memory>
//class TestB;
//class TestA
//{
//public:
// TestA()
// {
// std::cout << "TestA()" << std::endl;
// }
// void ReferTestB(std::shared_ptr<TestB> test_ptr)
// {
// m_TestB_Ptr = test_ptr;
// }
// void TestWork()
// {
// std::cout << "TestA::TestWork()" << std::endl;
// }
// ~TestA()
// {
// std::cout << "~TestA()" << std::endl;
// }
//private:
// std::weak_ptr<TestB> m_TestB_Ptr;//TestB的智能指针
//};
//class TestB
//{
//public:
// TestB()
// {
// std::cout << "TestB()" << std::endl;
// }
// void ReferTestA(std::shared_ptr<TestA> test_ptr)
// {
// m_TestA_Ptr = test_ptr;
// }
// void TestWork()
// {
// std::cout << "TestB::TestWork()" << std::endl;
// }
// ~TestB()
// {
// std::shared_ptr<TestA> tmp = m_TestA_Ptr.lock();
// tmp->TestWork();
// std::cout << "2 ref a:" << tmp.use_count() << std::endl;
// std::cout << "~TestB()" << std::endl;
// }
//private:
// std::weak_ptr<TestA> m_TestA_Ptr;//TestB的智能指针
//};
//int main()
//{
// std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
// std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
// ptr_a->ReferTestB(ptr_b);
// ptr_b->ReferTestA(ptr_a);
// std::cout << "1 ref a:" << ptr_a.use_count() << std::endl;
// std::cout << "2 ref b:" << ptr_b.use_count() << std::endl;
// return 0;
//}
//1、所有的对象最后都能正常释放,不会存在上一个例子中的内存没有释放的问题。
//2、ptr_a 和ptr_b在main函数中退出前,引用计数均为1,也就是说,在TestA和TestB中对std::weak_ptr的相互引用,
//不会导致计数的增加。在TestB析构函数中,调用std::shared_ptr<TestA> tmp = m_TestA_Ptr.lock(),
//把std::weak_ptr类型转换成std::shared_ptr类型,然后对TestA对象进行调用。
//13.std::function,std::bind封装可执行对象
//#include <functional>
//#include <iostream>
//
//class Test
//{
//public:
// typedef int(*FunType)(int, int);
// void Add(FunType fun, int a, int b)
// {
// int sum = fun(a, b);
// std::cout << "sum:" << sum << std::endl;
// }
//};
//
//int add(int a, int b)
//{
// return a + b;
//}
//
//int main()
//{
// Test test;
// test.Add(add, 1, 2);
// return 0;
//}
//假如add方法在TestAdd类内部,那你的Test类没辙了,因为Test里的Test函数只接受函数指针。
#include <functional>
#include <iostream>
class Test
{
public:
void Add(std::function<int(int,int)> fun, int a, int b)
{
int sum = fun(a, b);
std::cout << "sum:" << sum << std::endl;
}
};
int add(int a, int b)
{
return a + b;
}
class TestAdd
{
public:
int Add(int a, int b)
{
std::cout << "TestAdd::Add" << std::endl;
return a + b;
}
};
int main()
{
Test test;
test.Add(add, 1, 2);
TestAdd testAdd;
test.Add(std::bind(&TestAdd::Add, testAdd, std::placeholders::_1, std::placeholders::_2), 1, 2);
test.Add([](int a, int b)->int {
std::cout << "lamda add fun" << std::endl;
return a + b; },
1, 2);
return 0;
}
//std::bind第一个参数为对象函数指针,表示函数相对于类的首地址的偏移量;
//testAdd为对象指针;
//std::placeholders::_1和std::placeholders::_2为参数占位符,表示std::bind封装的可执行对象可以接受两个参数。
//14.lamda表达式
//#include <iostream>
//int main()
//{
// auto add = [](int a, int b)->int
// {
// return a + b;
// };
// int ret = add(1, 2);
// std::cout << "ret: " << ret << std::endl;
//}
//第3至5行为lamda表达式的定义部分
//[]:中括号用于控制main函数与内,lamda表达式之前的变量在lamda表达式中的访问形式;
//(int a, int b):为函数的形参
//->int:lamda表达式函数的返回值定义
//{}:大括号内为lamda表达式的函数体。