带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(4)

简介: 带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(4)

带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(3)https://developer.aliyun.com/article/1340927?groupCode=taobaotech


Assert的使用

Assert在pc时代是作为一个广泛(甚至是烂泛)使用的警告处理方式,在移动端以及类unix系统中,debug下表现通常会比windows更加猛烈些,通常是阻塞式的处理,特别是移动端会导致程序继续运行不下去,不像windows个框给你一个continue的选项。

因此在跨端开发中应避免直接使用assert,可以考虑使用重定义后的assert,同时合情合理使用重定义后的assert。

 

#ifdef NDEBUG
#define ALOG_ASSERT(_Expression) ((void)0)
#else
#define ALOG_ASSERT(_Expression) do {

 

5

...

\ 这里可以额外做error级别日志输出,是否进行assert阻塞式处理。

6

if(HandleAssert())

\

7

{

\

8

assert(_Expression);

\

9

}

\

10

} while (false)

 

11

#endif

 

 

 

关于继承

 

Composition is often more appropriate than inheritance. When using inheritance, make it public.

 

google的这个定义应该还是非常准确的,通常组合比继承更合适,即时要使用也必须是publice的方式。应尽量保“is a”的情况下使用继承,如果你想使用私有继承, 你应该替换成把基类的实例作为成员对象的方式。

 

对于重载的虚函数或虚析构函数, 使用 override, 或 (较不常用的) final 关键字显式地进行标记. 在部分clang编译器下,编译器要求务必显示声明,否则会报错,ms则没有此类要求。

 

关于Static变量

 

感兴趣的小伙伴可以研究一下c++的特性““Dynamic Initialization and Destruction with Concurrency”,其中里面有定义静态、动态变量析构的顺序,线程生命周期的对象全部在静态变量之前析构,静态变量按照后构造的先析构的栈式顺序释放。实际在实践中发现apple的clang编译器和运行时库对c++11的这个特性支持,未实现静态变量析构的多线程安全。

 

因此在目前阶段,如果有用到全局静态变量时需要考虑到析构多线程安全的问题,否则线上在个别平台会发生crash。

 


一个比较简单的思路:从全局静态变量替换为局部静态变量且不释放,直到进程被kill。这里还有一个变相的好处:  把加载时机从load变成了此代码段真正运行时。

 

eg:
old:
static std::recursive_mutex& m_mutex;
new:
static std::recursive_mutex& mutex() 
{
static std::recursive_mutex& mutex = *(new std::recursive_mutex());
return mutex;
  }

 

关于模板

 

模板的出现极大的方便了程序员,在未进入跨终端领域之前,虽了解它的一些诟病(代码膨胀&不合理的使用带来的性能损耗),也一直认为是一个非常棒的feature,随着移动端对包大小的要求越来越严格,模板的使用在跨终端    上被限制,需要更为合理的使用,否则将膨胀的非常厉害。在漫长的去模板化过程中有些经验值可以输出,供大家参考。

  1. 在涉及到移动端的跨终端开发里,应尽量避免使用模板,除非它带来足够多的收益,比如json序列化,通篇用cjson的方式替换,从开发体验和代码膨胀比上来看,替换就显得不值得,比如自定义std标准容器,看似省了不少膨胀,但是代码的维护性和可读性降低了很多,同样不值得替换。
  2. 尽可能选择小的模板编译单元,比如原来一个模板类,改为类里的模板函数
  3. 通常情况下模板可以以各种方式被除去,这里不是说在裸写一遍模板换实参的方法。
  4. 应尽可能的减少模板膨胀的速度,换句话说如果有可能应该尽量限制模板被特化的可能,譬如,我们的日志序列化,对于任意struct或者class在实现了ToString()方法后均可以实现日志自动化输出,任意类型在进入到LOG_IMPL中都会生成一份具体类型的实体,经过略微改造后,限制需要被序列化的类型需要显示继承IOBJECT的接口类,改造后,在同样进入到LOG_IMPL中所有的类型只会有一份类型(IOBJECT*)实化,此举在实践过程中大约减少了我们五分之一的包大小。
  5. 在多重继承中,特别是公共模块基类如果包含模板,去模板的收益一般会比较大,因尽量限制基类中出现模板, 除非必要,否则应以任何方式替换。

 

最后再插一嘴,模板对于使用者确实是极大的方便,但是在跨终端领域似乎对于模板的构建者有着更为严格的要求,需要着重考虑如何避免被膨胀,此外对于性能的要求也更为严格,c++11里有不少提供模板性能的方式,&&配 合std::forward实现完美转发,等等,有兴趣的可以看下《Effective Modern C++》。

 

以上也适用于 宏。

 

带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(5)https://developer.aliyun.com/article/1340925?groupCode=taobaotech

相关文章
|
8月前
|
JavaScript Unix 编译器
带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(2)
带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(2)
|
8月前
|
编译器 Linux C++
带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(3)
带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(3)
|
8月前
|
Linux 程序员 C语言
带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(1)
带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(1)
|
8月前
|
Unix Java 编译器
带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(5)
带你读《2022技术人的百宝黑皮书》——19条跨端cpp开发有效经验总结(5)
|
8月前
|
存储 异构计算
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(6)
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(6)
|
8月前
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(4)
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(4)
|
8月前
|
存储
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(5)
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(5)
|
8月前
|
C++ iOS开发
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(3)
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(3)
|
8月前
|
JSON Android开发 iOS开发
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(1)
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(1)
104 0
|
8月前
|
API iOS开发 C++
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(2)
带你读《2022技术人的百宝黑皮书》——Flutter 新一代图形渲染器 Impeller(2)
124 0