Skip to Content
C++Google 特有的魔法

Google 特有的魔法

我们使用各种技巧和工具来使 C++ 代码更加健壮,以及我们使用 C++ 的各种方式可能与你在其他地方看到的不同。

所有权和智能指针(Smart Pointers)

优先为动态分配的对象设置单一、固定的所有者。优先使用智能指针转移所有权。

“所有权(Ownership)“是一种用于管理动态分配内存(和其他资源)的簿记技术。动态分配对象的所有者是负责确保在不再需要时删除它的对象或函数。 所有权有时可以共享,在这种情况下,最后一个所有者通常负责删除它。即使所有权不共享,它也可以从一段代码转移到另一段代码。

“智能”指针是行为类似指针的类,例如通过重载 *-> 运算符。某些智能指针类型可用于自动化所有权簿记,以确保这些职责得到履行。std::unique_ptr 是一种表达动态分配对象独占所有权的智能指针类型;当 std::unique_ptr 离开作用域时对象被删除。它不能被拷贝,但可以被移动以表示所有权转移。std::shared_ptr 是一种表达动态分配对象共享所有权的智能指针类型。std::shared_ptr 可以被拷贝;对象的所有权在所有拷贝之间共享,当最后一个 std::shared_ptr 被销毁时对象被删除。

  • 没有某种所有权逻辑,几乎不可能管理动态分配的内存。
  • 转移对象的所有权可能比复制它更便宜(如果可以复制的话)。
  • 转移所有权可能比”借用”指针或引用更简单,因为它减少了两个用户之间协调对象生命周期的需要。
  • 智能指针可以通过使所有权逻辑显式、自文档化和无歧义来提高可读性。
  • 智能指针可以消除手动所有权簿记,简化代码并排除大类错误。
  • 对于 const 对象,共享所有权可以是深拷贝的一种简单且高效的替代方案。
  • 所有权必须通过指针(无论是智能的还是普通的)来表示和转移。指针语义比值语义更复杂,尤其是在 API 中:你不仅要担心所有权,还要担心别名、生命周期和可变性等问题。
  • 值语义的性能成本往往被高估,因此所有权转移的性能好处可能不足以证明可读性和复杂性成本是合理的。
  • 转移所有权的 API 迫使其客户端采用单一的内存管理模型。
  • 使用智能指针的代码对资源释放发生在哪里不太明确。
  • std::unique_ptr 使用移动语义表达所有权转移,这可能很复杂,可能让一些程序员感到困惑。
  • 共享所有权可能是精心所有权设计的诱人替代方案,使系统设计变得模糊。
  • 共享所有权需要运行时的显式簿记,这可能代价高昂。
  • 在某些情况下(例如循环引用),具有共享所有权的对象可能永远不会被删除。
  • 智能指针不是普通指针的完美替代品。

如果需要动态分配,优先将所有权保留在分配它的代码中。如果其他代码需要访问该对象,考虑传递一个拷贝,或传递指针或引用而不转移所有权。优先使用 std::unique_ptr 使所有权转移显式化。例如:

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

没有非常好的理由,不要将代码设计为使用共享所有权。这样做的一个理由是避免昂贵的拷贝操作,但你应该只在性能好处显著且底层对象不可变(即 std::shared_ptr<const Foo>)时才这样做。如果你确实使用共享所有权,优先使用 std::shared_ptr

永远不要使用 std::auto_ptr。请使用 std::unique_ptr

cpplint

使用 cpplint.py 来检测风格错误。

cpplint.py 是一个读取源文件并识别许多风格错误的工具。它并不完美,有误报和漏报,但仍然是一个有价值的工具。

一些项目有关于如何从其项目工具运行 cpplint.py 的说明。如果你贡献的项目没有,你可以下载 cpplint.py 单独下载。

Last updated on