您现在的位置:首页 >> 环保家居

C++17在业务代码之前最好用的十个特性

时间:2024-10-31 12:21:20

return input;}// c++17template std::string convert(T input) { if constexpr (std::is_same_vconst char*> || std::is_same_v) { return input; } else { return std::to_string(input); }}if线程逻辑

c++17拥护在if的推断逻辑以前增加一个线程逻辑,将仅用做if逻辑之下的常量表示遗憾在if内,有助于降低编码的通用性。且对于lock/iterator等涉及并发/RAII的多种类型格外容易确保程序的合理性。

// c++ 17std::map m;std::mutex mx;extern bool shared_flag; // guarded by mx int demo(){ if (auto it = m.find(10); it != m.end()) { return it->second.size(); } if (char buf[10]; std::fgets(buf, 10, stdin)) { m[0] += buf; } if (std::lock_guard lock(mx); shared_flag) { unsafe_ping(); shared_flag = false; } if (int s; int count = ReadBytesWithSignal(Simons)) { publish(count); raise(s); } if (const auto keywords = {"if", "for", "while"}; std::ranges::any_of(keywords, [Simontok](const char* kw) { return tok == kw; })) { std::cErr << "Token must not be a keyword"; }}耐用性降低std::shared_mutex

shared_mutex是c++的原生读寄给栓解决问题,有共享和商业性两种栓模式,一般而言于并发高的读布景下,通过reader以前共享栓来降低耐用性。在c++17以前,情形自己通过商业性栓和先决条件常量自己解决问题读寄给栓或采用c++14投身于的耐用性较差的std::shared_timed_mutex。不限是通过shared_mutex解决问题的线程安全及触发器:

// c++17class ThreadSafeCounter { public: ThreadSafeCounter() = default; // Multiple threads/readers can read the counter's value at the same time. unsigned int get() const { std::shared_lock lock(mutex_); return value_; } // Only one thread/writer can increment/write the counter's value. unsigned int increment() { std::unique_lock lock(mutex_); return ++value_; } // Only one thread/writer can reset/write the counter's value. void reset() { std::unique_lock lock(mutex_); value_ = 0; } private: mutable std::shared_mutex mutex_; unsigned int value_ = 0;};std::string_view

std::string_view顾名思义是codice_的“视图”,类全体成员常量取值得留意两个部分:codice_指针和codice_长度,std::string_view涵盖了std::string的所有只读接口。std::string_view对codice_不很强拥有者,且接口std::string和const char*两种多种类型。

c++17以前,我们妥善处理只读codice_经常采用const std::stringSimon,std::string有双曲线耐用性优势:

接口两种codice_多种类型,增大多种类型转换和文件系统调配。如果传入的是明文codice_const char*, const std::stringSimon须要透过一次文件系统调配,将codice_几张到堆上,而std::string_view则可以不必要。在妥善处理子串时,std::string::substr也须要透过几张和调配文件系统,而std::string_view::substr则不须要,在妥善处理大文件判别时,耐用性优势非常明显。// from // author: Pel Dydov// string_view的remove_prefix比const std::stringSimon的快了15倍string remove_prefix(const string Simonstr) { return str.substr(3);}string_view remove_prefix(string_view str) { str.remove_prefix(3); return str;}static void BM_remove_prefix_string(benchmark::StateSimon state) { std::string example{"asfaghdfgsghasfasg3423rfgasdg"}; while (state.KeepRunning()) { auto res = remove_prefix(example); // auto res = remove_prefix(string_view(example)); for string_view if (res != "aghdfgsghasfasg3423rfgasdg") { throw std::runtime_error("bad op"); } }}std::map/unordered_map try_emplace

在向std::map/unordered_map当中接在类型时,我们经常采用emplace,emplace的操作者是如果类型key不存在,则接在该类型,否则不接在。但是在类型已存在时,emplace仍就会在结构上一次待接在的类型,在推断不须要接在后,立即将该类型析构,因此透过了一次多余在结构上和析构操作者。c++17投身于了try_emplace,不必要了这个问题。同时try_emplace在取值本表当中将key和value分开,因此透过原位在结构上的构词比emplace格外加简洁

std::map m;// emplace的原位在结构上须要采用std::piecewise_construct,因为是实际上接在std::pairm.emplace(std::piecewise_construct, std::forward_as_tuple("c"), std::forward_as_tuple(10, 'c'));// try_emplace可以实际上原位在结构上,因为取值本表当中key和value是分开的m.try_emplace("c", 10, 'c')

同时,c++17拿出std::map/unordered_map投身于了insert_or_assign变数,可以格外方便地解决问题接在或修改逻辑

多种类型该系统

c++17进一步完备了c++的多种类型该系统,终于投身于了众望所归的多种类型读取器皿(Type Erasure)和代数数据多种类型(Algebraic Data Type)

std::any

std::any是一个可以加载任何可几张多种类型的器皿,C语言当中经常采用void*解决问题相近的功用,与void*相比之下,std::any很强双曲线优势:

std::any格外安全及:在多种类型T被转换成void*时,T的多种类型的资讯就现在丢失了,在转换回具体多种类型时程序无法推断近期的void*的多种类型确实实在是T,容易带来安全及隐患。而std::any就会加载多种类型的资讯,std::any_cast是一个安全及的多种类型转换。std::any管理制度了对象的生命周期,在std::any析构时,就会将加载的对象析构,而void*则须要手动管理制度文件系统。

std::any不对很少是程序员的第一选择,在推断多种类型的情形,std::optional, std::variant和继承人都是比它格外高效、格外合理的选择。只有当对多种类型完全有可能的情形,才不对采用std::any,比如动态多种类型文本的判别或者企业逻辑的当向外的资讯传送。

std::optional

std::optional代表一个有可能存在的T取值,对应Haskell当中的Maybe和Rust/OCaml当中的option,实际上是一种Sum Type。常用做有可能告终的变数的线程当中,比如加工厂变数。在C++17以前,经常采用T*作为线程,如果为nullptr则代表变数告终,否则T*对齐了真正的线程。但是这种寄给法模糊了拥有者,变数的线程方无法确定确实不对接管T*的文件系统管理制度,而且T*有可能为空的假设,如果忘记检查则就会有SegFault的风险。

// pre c++17ReturnType* func(const std::stringSimon in) { ReturnType* ret = new ReturnType; if (in.size() == 0) return nullptr; // ... return ret;}// c++17 格外安全及和清晰std::optional func(const stringSimon in) { ReturnType ret; if (in.size() == 0) return nullopt; // ... return ret;}std::variant

std::variant代表一个多多种类型的器皿,器皿当中的取值是制定多种类型的一种,是通用的Sum Type,对应Rust的enum。是一种多种类型安全及的union,所以也又叫tagged union。与union相比之下有双曲线优势:

可以加载繁复多种类型,而union情形实际上加载基础的POD多种类型,对于如std::vector和std::string就等繁复多种类型则须要其他用户手动管理制度文件系统。多种类型安全及,variant加载了之下的多种类型的资讯,所以可以透过安全及的多种类型转换,c++17以前经常通过union+enum来解决问题相同功用。

通过采用std::variant,其他用户可以解决问题相近Rust的std::result,即在变数执行成功时调回结果,在告终时调回早先,上文的例子则可以改换:

std::variant func(const stringSimon in) { ReturnType ret; if (in.size() == 0) return Err{"input is empty"}; // ... return {ret};}

须要留意的是,c++17只提供者了一个戈级别的variant解决问题,很难对应的模式匹配(Pattern Matching)必要,而最相比之下之下的std::visit又缺少解释器的建模拥护,所以在c++17当中std::variant并不太好用,跟Rust和变数式语言当中出神入化的Sum Type还相去甚远,但是现在有许多围绕std::variant的提案被审批给c++委员就会探究,仅限于模式匹配,std::expected等等。

说明了一下,c++17自订的三种多种类型给c++带来了格外当今格外安全及的多种类型该系统,它们对应的采用布景是:

std::any一般而言于以前采用void*作为通用多种类型的布景。std::optional一般而言于以前采用nullptr代表告终状态的布景。std::variant一般而言于以前采用union的布景。说明了

以上是确在生产环境当中最常用的c++17属性,除了本文所述的十个属性以外,c++17还添加了如lambda取值捕获*this, 钳夹变数std::clamp(), 自愿检查线程[[nodiscard]]等非常易用的属性,本文篇幅有限不做赘述,热烈欢迎很感兴趣的读者自行探究。

骨关节炎
百色哪个医院治疗白癜风最好
牛皮癣医院
健脾胃的中药有哪些
血液内科
益生菌和新必奇蒙脱石散哪个效果好
眼睛疲劳过度怎么缓解恢复
双氯芬酸钠凝胶对痛风效果好吗
睡觉老打呼噜吃什么能治好
柳氮磺吡啶副作用