一、decltype 获取类型
typeid(a).name()
int i = 0; decltype(i) j = 0; cout << typeid(j).name() << endl;
二、编译选项 -as-needed
- g++ -std=c++11 -o exe_main main.cpp 默认是 -as-needed
- g++ -Wl,--no-as-needed -std=c++11 -o exe_main main.cpp
- g++ -std=c++11 -o exe_main main.cpp -lpthread
上面3个编译之后执行崩溃报错:
terminate called after throwing an instance of 'std::system_error'
what(): Enable multithreading to use std::thread: Operation not permitted
Aborted
-as-needed 就是忽略链接时没有用到的动态库
--no-as-needed 就是不忽略链接时没有用到的动态库
g++ -Wl,--no-as-needed -std=c++11 -o exe_main main.cpp -lpthread 这样编译之后执行正确
三、strace 跟踪执行
root@ubuntu:/home/guohua# strace ./fftest
execve("./fftest", ["./fftest"], [/* 28 vars */]) = 0
brk(0) = 0x237c000
access("/etc/ld.so.nohwcap", F_OK) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffd01a4c000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/tang/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/tang/lib", {st_mode=S_IFDIR|0755, st_size=24576, ...}) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=78567, ...}) = 0
mmap(NULL, 78567, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ffd01a38000
close(3) = 0
四、移动构造
A a; //以下1只发生一次移动构造,比2少一次赋值构造和一次拷贝构造
- new A(std::move(a));// 只发生一次移动构造接管原来的a;
- A a1 = std::move(a); //发生一次移动构造,然后是赋值构造
new A(a1);//拷贝构造
可见 new std::string(std::move(data)) 只发生一次移动拷贝,新的string接管原来string的data,不发生实际的数据拷贝,开销较小
void test_thread(){
A a;
//A a1 = std::move(a);
//new A(a1);
new A(std::move(a));
printf("begin put thread param A\n");
std::thread thread_ = std::thread([&](){
a.hello();
});
printf("end put thread param A\n");
thread_.join();
/*[=](){} lamda表达式传值,1次赋值拷贝,再是1次拷贝构造,2次移动构造
I'm A
begin put thread param A
I'm operator= A
I'm copy A
I'm move A
I'm move A
I'm ~A
hello A
I'm ~A
I'm ~A
end put thread param A
I'm ~A
*/
/*[&](){} lamda表达式传引用,没发生任何构造
I'm A
begin put thread param A
end put thread param A
hello A
I'm ~A
*/
}
五、C++11 一些新特性
1. std::forward_list
新增的线性表,与list区别在于它是单向链表。
std::forward_list<int> numbers = {1,2,3,4,5,4,4}; numbers.remove(4);
2. std::unordered_map
与std::map用法基本差不多,但STL在内部实现上有很大不同,std::map使用的数据结构为二叉树,而std::unordered_map内部是哈希表的实现方式,哈希map理论上查找效率为O(1)。但在存储效率上,哈希map需要增加哈希表的内存开销。
std::unordered_map<std::string, std::string> mymap = { { "house","maison" } };
unsigned n = mymap.bucket_count();
3. std::unordered_set
数据存储结构也是哈希表的方式结构,除此之外,std::unordered_set在插入时不会自动排序。
4. std::thread 线程对象
#include <thread> std::thread t1(threadfun1); std::thread t2(threadfun2, 10, "abc"); std::thread([=](){}) t.join(); t.detach();
5. std::atomic 原子操作
大括号初始化 std::atomic_bool is_valid_{ false };
6. std::condition_variable 条件变量
需要条件变量cv、锁和条件共同完成。
锁只是保护共享资源或者临界区互斥访问,访问完就失去保护。临界区是需要不断检测某个条件是否满足时,如果没有条件变量机制,那就需要不断的轮询检测,引入条件变量之后,在临界区检测条件不满足时挂起等待,等这个条件在另外一个线程触发满足时唤醒。类似于select机制,只是select监听的是fd,条件变量监听的是一般的条件。
#include <condition_variable> std::condition_variable cv; // 对应 pthread_cond_t
离不开锁 std::mutex mtx; 使用的是 unique_lock
std::unique_lock<std::mutex> lck(mtx);//std::mutex对应pthread_mutex_t,unique_lock() 对应 pthread_mutex_lock();
cv.wait(lck);//{ cv不满足lck.unlock()解除对临界资源的锁定,把当前线程加入等待队列 pthread_cond_wait(cv),阻塞,唤醒之后lck.lock()继续锁定资源。cv.wait()对应pthread_cond_wait();
在子线程中需要对条件变量cv加锁之后调用wait阻塞着等待资源,如果wait的时候不传锁进去,那阻塞的时候锁就得不到释放,外面其他共用锁的地方就拿不到锁,所以把锁传进wait内部就是为了阻塞的时候释放锁给外面的线程使用,等阻塞结束(被唤醒)再继续锁上。这也是为啥cv选择 unique_lock 的原因,因为 unique_lock 提供了lock()和unlock()的操作。
std::unique_lock<std::mutex> lck(mtx); cv.notify_all();//对应 pthread_cond_broadcast(),cv.notify()对应 pthread_cond_signal()。
7.std::function、std::bind
std::function 接受函数对象
void Add(std::function<int(int, int)> fun, int a, int b){ int sum = fun(a, b); std::cout << "sum:" << sum << std::endl; } std::bind 可绑定全局函数,类函数 test.Add(std::bind(&TestAdd::Add, testAdd, std::placeholders::_1, std::placeholders::_2), 1, 2);