I.11: 永远不要使用原始指针(T*)或引用(T&)来转移所有权
原因
如果对调用者或被调用者是否拥有对象有任何疑问,就会发生泄漏或过早析构。
示例
考虑:
X* compute(args) // 不要这样做 { X* res = new X{}; // ... return res; }
谁来删除返回的X?当compute返回一个引用时,则更难发现问题。考虑按值返回结果(如果结果很大,使用move语义):
vector compute(args) // good { vector res(10000); // ... return res; }
可选方法: 传递所有权 使用"智能指针",如unique_ptr(独占所有权)和shared_ptr(共享所有权),然而,这并不会比返回对象本身更优雅和高效,所以只有在需要引用语义时才使用智能指针。
可选方法: 有时,由于ABI的兼容性要求和资源缺失,导致更旧代码无法修改,在这种情况下,使用指南支持库中的owner标记拥有指针:
owner compute(args) // 现在很清楚,所有权已经转移 { owner res = new X{}; // ... return res; }
这告诉分析工具res是所有者,也就是说,它的值必须被delete或转移到另一个所有者,就像这里的return所做的那样。owner在资源句柄的实现中有也类似应用。
Note
作为原始指针(或迭代器)传递的每个对象都假定为调用者所拥有,因此它的生命周期由调用者处理。从另一个角度来看:与指针传递API相比,所有权转移API相对较少,因此默认为“无所有权转移”。
另请参阅: 参数传递、 智能指针参数的使用 和 按值返回.
实施
- (简单) 警告delete非owner的原始指针,建议使用标准库资源句柄或使用owner。
- (简单) 每条代码路径上reset或显式delete一个owner指针时,警告失败。
- (简单) 如果new的返回值或带owner返回值的函数调用被分配给原始指针或非owner引用,则发出警告。