-
背景 每一个cpp expression都有一个type 和 value category 属性 前者大家都比较了解,但是后者却常常被忽视 Value Categories in the c language cpp是由c语言发展而来,因此这里先介绍c 语言中的value category c语言只有简单的lvalue和rvalue两种 lvalue lvalue的"l"表示"left",表示lvalue可以出现在assigment operator的左边 更准确的说 Tip "lvalue is a value refer to an object" "an …
Read More -
概述 std::shared_ptr是智能指针的一种,在modern c++中被广泛使用(甚至滥用) 虽然天天使用,但是有些细节还不是100%清楚,因此来整理一下 为了方便表述,下文只写shared_ptr,不在写std的namespace. 组成 shared_ptr的实现中,成员通常由两部分组成。一个是所涵盖对象的指针,一个是control block 的指针 control block Tip 最重要的是,control block是 dynamically-allocated 的 (校招的时候某次面试,让我手写shared_ptr的实现,当时被多个object如何共享引用计数卡住了。。主要就是没意识到control …
Read More -
背景 一种很常见的背景是,需要表示未知类型的数据。 比如可能是用户提供的数据,比如是一个Cache的实现, value想支持任意类型的数据 对于这种场景,c语言的出身的开发者通常会使用void*来实现 1struct day { 2 // ...things... 3 void* user_data; 4}; 5 6struct month { 7 std::vector<day> days; 8 void* user_data; 9}; 10 了解cpp11的开发者可能会使用std::shared_ptr<void> 来实现 1struct day { 2 // ...things... 3 …
Read More -
把std::async,std::packaged_task,std::promise三个放在一起来说,是因为他们都可以返回一个std::future对象.简单来说,当某个线程需要等待一个特定的一次性事件(one-off event),它可以用一个"future"来表示这个事件. std::async 有的时候可能你需要做一个花费事件比较长的计算,但是计算结果不是立刻需要.这个时候就可以用一个新的线程来做这个计算.这里比较关键的问题是如何将在新线程进行计算的结果传回到当前线程,因为std::thread并没有提供一个类似的机制. 这个时候就需要std::async登场了. 1 2 #include …
Read More -
condition_variable 类是同步原语,能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable 。 用人话来说,condition_variable,也就是条件变量,是线程间通信的一种方式。 线程之间在很多时候需要通信,比如经典的生产者消费者问题 一个比较naive的方案是,用mutex来保护一个flag,然后另一线程不停得check这个flag的状态是否改变。以及在这个方案上的改进:让另一个线程check之后,可以先睡一段时间。 但是这两种方法都不够好。第一种不好的原因当然是不停得check,肯定会耗费大量的资源。而第二种,由于没办法准确估计要休眠的时间,因 …
Read More -
多线程保护数据时,一种较为特殊的情况是只需要保护资源的初始化。 资源初始化一般遵循"lazy initialization"的原则,也就是在用到该资源最近的地方再初始化。 比较容易想到的办法是用std::mutex,将资源初始化的地方锁起来,如下: 1 std::shared_ptr<some_resource> resource_ptr; 2 std::mutex resource_mutex; 3 void foo() 4 { 5 std::unique_lock<std::mutex> lk(resource_mutex); 6 if(!resource_ptr) 7 { 8 …
Read More -
背景 move semantics是modern cpp中非常重要的特性,有必要详细了解一下。 updateime: 2022年7月2日 move semantic 基本的内容大家都很熟悉,就不说了 std::move 做了什么 std::move没有move任何内容,只是简单把传进来转换为对应的rvalue reference 实现为: 1 2template<typename T> 3constexpr std::remove_reference_t<T>&& move(T&& t) noexcept 4{ 5 return …
Read More -
起因是在看《CplusplusConcurrencyInAction_PracticalMultithreading》的时候,里面讲到初始化std::thread的时候,如果thread funtion的参数列表中有引用,需要传入std::ref才可以得到符合预期的结果。 查阅发现std::ref是用来生成std::reference_wrapper。 按照 cppreference 上的话来说 `std::reference_wrapper` 是包装引用于可复制、可赋值对象的类模板。它常用作将容器存储入无法正常保有引用的标准容器( …
Read More -
最近在学习node.js,里面讲到node.js的事件机制使用了观察者模式,因此来学习一下。 观察者模式的目的是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 因此观察者模式又叫发布-订阅模式。 下面放一个简化之后的例子: 1 2 3 #include <iostream>4 #include <vector>5 #include <string>6 using namespace std; 7 class Secretary; 8 // 看股票的同事类(观察对象,观察者) 9 class StockObserver 10 { 11 …
Read More -
用人话就是,主线程传给附属线程一个promise Object,然后主线程想要获取附属线程set给promise Object的值(也就是该线程返回的某个结果),需要通过主线程中的promise object 得到对应的future object(每个promise 对应一个 future),然后调用future 的get方法。如果附属线程没有执行作为参数传入的promise的set方法去返回结果,那么程序就会block住。 1 /* *********************************************** 2Author :111qqz 3mail: renkuanze@sensetime.com …
Read More