0%

记录编写 C++ 代码过程中的疑惑、避坑的技巧等

深入理解 C++

模板遇上 DLL 导出

模板是为了共用代码,使用模板时首先要完成实例化,而实例化要求看到模板的完整定义才可以。所以,如果给用户使用暴露模板,就要暴露模板的实现细节。

DLL 是为了隐藏实现,只给用户暴露使用的接口,其中的具体实现用户是看不到的,也不需要关心。DLL 包装起来的是类的定义,而不是模板。所以,不存在“导出模板”,如果暴露模板定义给用户,那么用户是应当看到模板所有细节的,直接使用模板实例化(类或者函数)来用即可。

如果不想暴露具体的实现,只能先实例化成具体的类或函数,然后将类或者函数导出。

阅读全文 »

这里不讲条件变量 std::conditional_varibale 的具体使用,自行上 cppreference 网站查阅手册。

条件变量

std::condition_variable 类型描述

在 pthread 中条件变量的惯用手法是将 wait 放在 while 循环中。在 C++11 之后,常见的书写形式为

1
2
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});

其完全等价于循环方式,而将 wait 放到循环中,主要是因为虚假唤醒的存在。

此重载可用于在等待特定条件成为 true 时忽略虚假唤醒。

初次之外,还有 wait_forwait_util

阅读全文 »

1
2
3
4
5
// OK
for (auto itor = _functionCode.cbegin(); itor != _functionCode.cend(); ++itor)
// ERR
for (auto const itor = _functionCode.cbegin(); itor != _functionCode.cend(); ++itor)
// why?

auto 能够自动推导常量吗?引用呢?——不能!

auto 一般会忽略掉顶层 const,如果希望推导出的 auto 类型是一个顶层 const,需要明确指出。P66

可以将引用的类型设为 auto,此时原来的初始化规则仍然使用。设置一个类型为 auto 的引用时,初始值中的顶层常量属性仍然保留。P66

const_iterator 可以读取元素,但不能修改元素的迭代器类型

阅读全文 »

using 指示,第 703 页,两种使用场景:

  • using declaration 声明 using std::cout;
  • using directive 指示 using namespace std;

using 指示(using directive)和 using 声明类似的地方是,我们可以使用命名空间名字的简写形式;和 using 声明不同的地方是,我们无法控制哪些名字是可见的,因为所有名字都是可见的。

后者不能用在类作用域中;前者虽然能用在类作用域中但只能指向基类成员。更多知识请进一步学习《C++ Primer》

75 页明确提到头文件中不应使用 using 声明:

位于头文件的代码一般来说不应该使用 using 声明。这是因为头文件的内容会拷贝到引用它的文件中去,如果头文件有某个 using 声明,那么每个使用了该头文件的文件就都会有这个声明。对应某些程序来说,由于不经意间包含了一些名字,反而可能产生始料未及的名字冲突

702 页提到使用 using 指示也可能造成名字冲突问题:

如果我们提供了一个对 std 等命名空间的 using 指示而未做任何特殊控制的话,将重新引入由于使用了多个库而造成的名字冲突问题。

在源文件中使用 using 指示是否能够接受呢?能够节省大量的重复代码,注意规避名字冲突即可——除非源文件引入了较多的三方库,名字冲突并不常见。

学习 locale 和编码转换过程中的关键以及问题。

  • 不使用 locale,无法完成编码转换吗?Unicode 自身的 utf-8/16/32 的 存储方式之间的转换 也不行吗?
  • utf-8 对应 charstring;utf-16 对应 wchar_t/wstring,这种理解对吗?所以 boost::locale::conv::to_utf<char>() 就是转 utf-8(而不是 utf-16/32)?boost::locale::conv::to_utf<wchar_t>() 就是转 utf-16 (或 utf-32)?
  • 本地化策略集 locale 和程序运行有关系吗? #139
  • C++17 为什么弃用了 <codecvt>?且 尚无替换方案 吗?
  • 都有哪些本地化策略可选呢?
  • 如果统一使用 Unicode 编码(utf-8/16/32 存储方式无所谓),是否就不需要本地化策略 locale了?它是源于上世纪各个国家、地区闭门造车,独自扩展 ANSI 字符集带来的后果吧?
  • C++11 - Convert to/from UTF-8/wchar_t 里面提到的 UTF8-CPP 和 NoWide 分别是什么?

没有一致的 locale name o(╥﹏╥)o,windows 编程时怎么写

Locale names are not part of the C++ standard… 引用来源

关联问题:

  1. What is the Windows equivalent for en_US.UTF-8 locale?
  2. How to change system locale in Windows 10
阅读全文 »

减少头文件的依赖。

Pimpl Idiom

《Effective C++》 条款31:将文件间的编译依存关系降至最低

《Effective Modern C++》 Item 22: When using the Pimpl Idiom, define special member functions in
the implementation file.

在其单例模式的基础上,使用 Interface class(工厂模式)而非 Handle class(Pimpl Idiom)更合适

参考 tnie/learn_xxx 中 coro 项目。

如果想看懂 asio 如何支持 co_await 的,想更细致地用好协程,就需要了解更基础(同时也是更复杂的)内容。

第一章

微软专家 C++ coroutines: Getting started with awaitable objects 开篇的陈述,比我的倾向更具说服力:

Coroutines were added to C++20, and Lewis Baker has a nice introduction to them.

特别推荐这几篇文章,作者写了 cppcoro 库,牛人!

首推,此系列的文章作为入门。

对协程介绍时,先介绍 awaitable/awaiterpromise。学习笔记/摘抄,见 coroutine-a~c.md

阅读全文 »

来源:https://lewissbaker.github.io/2018/09/05/understanding-the-promise-type

Coroutine Concepts

The compiler applies some fairly mechanical transformations to the code that you write to turn it into a state-machine that allows it to suspend execution at particular points within the function and then later resume execution.

编译器会对您编写的代码进行一些相当机械的转换,以将其转换为状态机,使状态机可以在函数内的特定点挂起执行,然后再恢复执行。

Promise objects

The Promise object defines and controls the behaviour of the coroutine itself by implementing methods that are called at specific points during execution of the coroutine.

阅读全文 »

来源:https://lewissbaker.github.io/2017/11/17/understanding-operator-co-await

What does the Coroutines TS give us?

The facilities the C++ Coroutines TS provides in the language can be thought of as a low-level assembly-language for coroutines. These facilities can be difficult to use directly in a safe way and are mainly intended to be used by library-writers to build higher-level abstractions that application developers can work with safely.

C ++ Coroutines TS 提供的功能可以被认为是协程的一种低级汇编语言。这些功能可能很难以安全的方式直接使用,并且主要旨在供库编写人员用来构建更高级的抽象,以便应用程序开发人员可以安全地使用它们。

Compiler <-> Library interaction

Instead, it specifies a general mechanism for library code to customise the behaviour of the coroutine by implementing types that conform to a specific interface. The compiler then generates code that calls methods on instances of types provided by the library.

它为库代码指定了一种通用机制,可通过 实现符合特定接口的类型 来自定义协程的行为。然后编译器调用 这些类型的方法 = 库提供的类型的实例的方法

There are two kinds of interfaces that are defined by the coroutines TS: The Promise interface and the Awaitable interface.

阅读全文 »