1、第一板块:内存管理: 1、实用动态内存的优势:不同的对象函数之间可以共享使用一个内存区域。 2、每一个New都有一个与之对应的delete进行释放。 3、new 和malloc的区别在于new不但分配了内存还同时创建对象,而malloc只负责分配内存。 4、直接声明数组和声明的new int[5];区别只在于他们存在的位置。 5、释放数组指针时候: delete [] HeadPtr ; HeadPtr=nullptr; 6、智能指针,shared_ptr内部有引用计数 unique_ptr而没有。通过智能指针实现自动释放内存。 share_pt<Simple> mySimpleSmartPtr(new Simple()); auto mySimpleSmartPtr=make_shared<Simple>(); 两种方法来实现智能指针。 同时需要引用<memory>头文件 7、原则:永远不要把内存分配的结果赋值给普通指针,不论是实用new还是malloc() 或其他的内存分配方法,将分配的结果赋值给智能指针share_ptr或unique_ptr. 8、不要使用share_ptr来管理C风格的数组的指针,通过unique_ptr管理C风格的数组,或者使用STL容器,而不是C风格数组。 2、第二部分:多线程编程: 1、多线程,导致资源争夺,资源争夺需要进行资源的死锁。std::lock()或std::try_lock()来实现加锁和测试加锁。 2、原子性的操作在<atomic>头文件中实用atomic<int> 等效atomic_int 调用join()等待所有的线程执行完毕。 3、使用<atomic>可以得到一个不需要显示加锁,且线程安全没有竞争条件的程序。 4、使用<thread>头文件创建一个线程,可以让新线程执行一个全局函数,一个函数对象的Operator(),一个lambda表达式,或者每个类的实例成员函数。threa类的构造函数是一个变参模板,可以接收任何参数。 5、多个线程调用每一个变量,要保证这个变量是线程安全的,可以通过A.sync_with_stdio(true);从而防止多个线程调用时产生竞争。 6、t.join()方法会导致调用线程的阻塞,更好的办法是通过事件机制,来实现线程执行完成后触发事件,通知相关UI线程。 7、使用C++11的新功能更能适用, #include <thread> #include <iostream> using namespace std; int main() { cout.sync_with_stdio(true); // Make sure cout is thread-safe thread t1([](int id, int numIterations) { for (int i = 0; i < numIterations; ++i) { cout << "Counter " << id << " has value "; cout << i << endl; } }, 1, 5); t1.join(); return 0; } 8、可以通过一个基类的成员函数来创建线程 Request req(100); thread t{&Request::Process,&req}; t.join(); 如果多个线程访问同一个对象,一定要保证对象是线程安全的。同时要考虑线程的互斥和同步机制。 9、线程的本地存储,可以通过thread_local来标记一个线程为本地线程,拥有自己的独立的对象副本。 thread_local int n; 10、线程互斥:多个线程访问同一个对象此时要考虑互斥问题。C++11 通过互斥体和锁来实现互斥操作。<mutex>头文件。 非定时的互斥体类:std::mutex 是一个标准的具有排他权予以的互斥体,一个已经拥有一个互斥体所有权的线程不能在这个互斥体上再次调用lock(),和try_lock()否则可能导致死锁。 std::recursive_mutex 与std::mutex 很类似,但区别在于可再次调用lock()和try_lock()。线程调用unlock()方法的次数应该等价于这个互斥体锁的次数。 支持以下方法: lock()调用线程将尝试获取锁,并且一直阻塞直到获得锁。 try_lock()调用将尝试获得锁,如果当前所被其他线程持有将立即返回,如果成功获得锁try_lock()返回true,否则返回false。 unlock():释放线程持有的锁,使另一个线程能够获得这个锁。 定时互斥体:std::timed_mutex std::recursive_timed_mutex try_lock_for(rel_tiem): 尝试在相对时间内得到一个锁,如果在规定时间内没能成功返回失败 try_lock_until(abs_time):调用线程将尝试获得这个锁,知道系统时间等于或大于这个时间 11:锁类 锁类是一个包装类,通过锁类可以更方便的获得和释放一个互斥体上的锁,锁类的析构函数会自动的释放关联的互斥体。 std::lock_guard 构造函数要求获得关联的互斥体,并且会阻塞知道获得锁 std::unique_lock 允许获得锁的时间延迟到计算需要的时间,远在声明之后,unique_lock有多个构造函数。 std::call_once()实现对多线程中涉及的只需要一次初始化的方法调用 call_once( mOnceFlag, &Data::init, this ); 12、互斥体的使用: 通过sync_with_stdio(true)时,C++的流线程是安全的,但是不同线程的输出任然是交错的,为了解决这一问题,可以引入一个互斥体对象,以确保在某个时间内只有一个线程正在读取/写入流对象。 13、条件变量 允许一个县城阻塞,直到另一个线程设置了某个条件或系统时间到达了某个指定的时间.<condition_variable>头文件来使用条件变量。 std::condition_variable 只能等待unique_lock<mutex>的条件变量 std::condition_variable_any 可以等待任何条件变量,包括自定义的锁类型。notify_one();notify _all(); wait(unique_lock<mutex>& lk); 14、如果一个线程抛出一个异常,而这个异常没有被线程本省处理,C++运行时将调用std::terminate,将会终止整个应用程序。通过std::future来避免这点,将没有捕捉的异常转移到另一个线程中,然后另一个线程可以在任意位置处理这个异常,原则上不能让一个线程的异常处理离开这个线程。 通过std::future和std::promise 可以使得同一个线程或另一个线程中函数返回的结果更容易取得。。