2. 多线程环境中,对于同一个std::shared_ptr实例 , 只有访问const的成员函数 , 才是线程安全的,对于非const成员函数,是非线程安全的,需要加锁访问 。
【C++常见避坑指南】首先来看一下 std::shared_ptr 的所有成员函数,只有前3个是 non-const 的,剩余的全是 const 的:
成员函数是否const operator=non-constresetnon-constswapnon-constgetconstoperator、operator->constoperatorconstuse_countconstoperator boolconstuniqueconst 讲了这么多,来个栗子实践下:
ant::Promise<JsAPIResultCode, CefRefPtr<CefDictionaryValue>>XXXHandler::OnOpenSelectContactH5(const JsAPIContext& context, std::shared_ptr<RequestType> arguments) { ant::Promise<JsAPIResultCode, CefRefPtr<CefDictionaryValue>> promise; base::GetUIThread()->PostTask(weak_lambda(this, [this, promise, context, arguments]() { auto b_executed_flag = std::make_shared<std::atomic_bool>(false); auto ext_param = xx::OpenWebViewWindow::OpenURLExtParam(); // ... // SelectCorpGroupContact jsapi的回调 ext_param.select_group_contact_callback = [promise, b_executed_flag]( JsAPIResultCode resCode, CefRefPtr<CefDictionaryValue> res) mutable { *b_executed_flag = true; base::GetUIThread()->PostTask([promise, resCode, res]() { promise.resolve(resCode, res); }); }; // 窗口关闭回调 ext_param.dismiss_callback = [promise, b_executed_flag]() { if (*b_executed_flag) { return; } promise.resolve(JSAPI_RESULT_CANCEL, CefDictionaryValue::Create()); }; // ... xx::OpenWebViewWindow::OpenURL(nullptr, url, false, ext_param); })); return promise;}该段代码场景是一个Jsapi接口,在接口中打开另一个webview的选人窗口 , 选人窗口操作后或者关闭时都需要回调下,将结果返回jsapi 。选人完毕确认后会回调select_group_contact_callback,同时关闭webview窗口还会回调dismiss_callback,这俩回调里面都会回包,这里还涉及多线程调用 。这俩回调只能调用一个 , 为了能简单达到这种效果,作者用std::shared_ptrstd::atomic_bool b_executed_flag来处理多线程同步,如果一个回调已执行就标记下,shared_ptr本身对引用计数的操作是线程安全的,通过原子变量std::atomic_bool来保证其管理的对象的线程安全 。
std::map// 定义数据缓存类class DataCache {private: std::map<std::string, std::string> cache;public: void addData(const std::string& key, const std::string& value) { cache[key] = value; } std::string getData(const std::string& key) { return cache[key]; }};在上述示例中,简单定义了个数据缓存类 , 使用 std::map作为数据缓存,然后提供addData添加数据到缓存,getData从map缓存中获取数据 。一切看起来毫无违和感,代码跑起来也没什么问题,但是如果使用没有缓存的key去getData, 发现会往缓存里面新插入一条value为默认值的记录 。
需要注意的是,如果我们使用 [] 运算符访问一个不存在的键,并且在插入新键值对时没有指定默认值,那么新键值对的值将是未定义的 。因此,在使用 [] 运算符访问 std::map 中的元素时 , 应该始终确保该键已经存在或者在插入新键值对时指定了默认值 。
void addData(const std::string& key, const std::string& value) { if(key.empty()) return; cache[key] = value;}std::string getData(const std::string& key) { const auto iter = cache.find(key); return iter != cache.end() ? iter->second : "";}sizeof & strlen相信大家都有过这样的经历,在项目中使用系统API或者与某些公共库编写逻辑时,需要C++与C 字符串混写甚至转换,在处理字符串结构体的时候就免不了使用sizeof和strlen,这俩看着都有计算size的能力,有时候很容易搞混淆或者出错 。
推荐阅读
- 沙滩裤最常见的面料有哪些 沙滩裤首选什么面料
- 7种常见水果,秋天吃正是好时候,健康促消化对吗
- 常见鸟类的本领和特征 常见鸟类的本领
- 八个 C++ 开源项目,帮助初学者进阶成长
- 买车分期与全款:内行揭秘,新手购车避坑指南
- 常见泵原理图 泵的结构与原理图
- U盘使用过程中常见问题及其解决方案
- SSL协议是什么?关于SSL和TLS的常见问题解答
- 衣服的常见面料,十大常见服装面料优缺点分析
- C++多线程编程:解锁性能与并发的奥秘
