现在的位置: 首页 > 综合 > 正文

GoogleCpp风格指南 4)Google奇技

2019年01月13日 ⁄ 综合 ⁄ 共 2713字 ⁄ 字号 评论关闭

4 来自Google的奇技 Google-Specific Magic

Google用了很多自己的实现技巧/工具使 C++代码更加健壮, 我们使用C++的方式可能和你在其他地方见到的有所不同;

[Removed]

4.1 智能指针

Tip 如果确实需要使用智能指针的话, scoped_ptr完全可以胜任; 你应该只在非常特定的情况下使用 std::tr1::shared_ptr, 例如STL容器中的对象; 任何情况下都不要使用 auto_ptr;

"智能"指针看上去是指针, 其实是附加了语义的对象; 以 scoped_ptr为例; scoped_ptr被销毁时, 它会删除所指向的对象; shared_ptr也是如此; 并且 shared_ptr实现了 引用计数, 所以最好一个 shared_ptr对象析构时, 如果检测到引用次数为0, 就会销毁所指向的对象;

一般来说, 我们倾向于设计对象隶属明确的代码, 最明确的对象隶属是根本不使用指针, 直接将对象作为一个作用域或局部变量使用; 另一种极端做法是, 引用计数指针不属于任何对象; 这种方法的问题是容易导致循环引用, 或者导致某个对象无法删除的诡异状态, 而且在每一次拷贝或赋值时连原子操作都会很慢;

虽然不推荐使用引用计数指针,但有些时候它们的确是最简单有效的解决方案;

(译注 看来Google所谓的不同之处, 在于尽量避免使用智能指针, 使用时也尽量局部化, 并且安全第一);

<<<

[Add] 

所有权和智能指针 Ownership and Smart Pointers

建议给动态分配的对象一个单独的固定的拥有者; 使用smart ptr来转移所有权;

定义:

"所有权"是一个记录技术bookkeeping technique, 用来管理动态创建的内存(和其他资源); 动态创建的对象的所有者是一个对象或一个函数, 负责保证对象在被删除的时候不再被使用; 所有权有时可以被共享, 这种情况下, 最后一个所有者负责删除它; 即便所有权没有被共享, 它也可以从一段代码转移到另一段; 

"Smart" pointer 是用起来像指针一个的类, e.g. 重载overload了 * 和 -> 操作符; 一些smart ptr类型可以用来将所有权记录自动化automate ownership bookkeeping, 确保这些责任和所有者对应;

std::unique_ptr (http://en.cppreference.com/w/cpp/memory/unique_ptr) 是一个smart ptr类型, 在c++11中引入, 表示对于动态创建的对象的专门的所有权; 当std::unique_ptr离开生命周期的时候,
对象会被删除; 它不能被copy, 但是可以用move来将所有权转移; 

std::shared_ptr http://en.cppreference.com/w/cpp/memory/shared_ptr 是一个smart ptr类型, 表示对于动态创建的对象的共享所有权; std::shared_ptr可以被copy, 对象的所有权可以在各份copy之间共享,
当最后一个std::shared_ptr被销毁的时候对象会被删除;

优点:

- 如果没有所有权逻辑的话, 无形中是不可能管理好动态分配的内存的;

- 转移对象的所有权比copy对象来得更轻便(如果可以copy的话);

- 转移对象的所有权比"borrowing"一个指针或引用更简单, 因为这样减少了在两个用户之间协调对象生存期的需求;

- Smart ptr可以让所有权逻辑清晰, 增加可读性, 自我文档式, 减少混淆; 

- Smart ptr去除了人工的所有权记录, 简化了代码, 排除错误error的大型类;

- 对于const对象, 比起深拷贝来说, 共享所有权可以更简单而有效;

缺点:

- 所有权必须由指针(smart或plain)来代表和转移; 指针的语义比值语义更复杂, 特别在API中, 你不得不在各种问题中考虑所有权, 别名, 生存期以及易变性mutability;

- 对值语义的性能消耗常常被高估了, 因此所有权转移带来的性能补助可能不及在可读性和复杂性上的损失;

- 转移所有权的APIs强制它们的客户使用一个单独的内存管理模型;

- 使用smart ptr的代码对于资源release的具体发生地点不明确; 

- std::unique_ptr使用c++11的move语义表达所有权转移, 这是相对较新的特性, 可能让一些程序员感到困惑;

- 共享所有权容易诱使人们不再进行仔细的所有权设计, 从而使得系统设计变得混乱; 

- 共享所有权需要在运行时进行显式地进行记录, 消耗比较昂贵;

- 在一些情况下(e.g. 循环引用cyclic references), 拥有共享所有权的对象可能永远的都不会被删除;

- Smart ptr并不是普通plain指针的完美替代;

结论:

如果必须进行动态分配, 建议将所有权保留在负责分配内存的代码部分; 如果另一块代码想要获取这个对象, 考虑传递一个copy, 或者传递一个指针或引用但不要传递所有权; 建议使用 std::unique_ptr来明确所有权传递;  e.g.

1
2
std::unique_ptr<Foo>
FooFactory();
void FooConsumer(std::unique_ptr<Foo>
ptr);

没有很好的理由的话, 不要将代码设计成共享所有权的; 一个原因是为了避免昂贵的copy操作; 要使用共享所有权条件是: 重大的性能获益, 操作对象是不可变的immutable(i.e. std::shared_ptr<const Foo>); 如果使用了共享所有权, 建议使用 std::shared_ptr;

不要在新代码中使用 scoped_ptr, 除非你想要和旧版本的C++保持兼容; 永远不要使用 std::auto_ptr, 用 std::unique_ptr代替它;  [http://stackoverflow.com/questions/13481579/unique-ptr-vs-auto-ptr ]

<<<


4.2 cpplint

Tip 使用 cpplint.py检查风格错误;

cpplint.py是一个用来分析源文件, 能检查出多种风格错误的工具; 它并不完美, 甚至会漏报和误报, 但它仍然是一个非常有用的工具; 用行注释 // NOLINT(行尾) // NOLINTNEXTLINE(前一行)可以忽略误报;

某些项目会指导你如何使用他们的项目工具运行 cpplint.py; 如果你参与的项目没有提供, 可以单独下载  http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py 

---TBC---YCR

抱歉!评论已关闭.