Smart Pointer Guidelines

What are smart pointers?

Smart pointers are a specific kind of "scoping object". They are like regular pointers but can automatically deallocate the object they point to when they go out of scope. Since C++ is not a garbage collected language, such functionality is important. The pattern where scoping objects are used to automatically manage the lifetime of heap-allocated objects is called RAII - Resource Acquisition IInitialization.

Here's some sample use of std::unique_ptr<>, the most common type of smart pointer:

// We can put a pointer into a std::unique_ptr<> at construction time...
std::unique_ptr value(base::JSONReader::Read(data));
std::unique_ptr foo_ptr(new Foo(...)); // ...or by using reset().
std::unique_ptr bar_ptr; // Like "Bar* bar_ptr = nullptr;".
bar_ptr.reset(new Bar(...)); // Now |bar_ptr| is non-nullptr and owns the object. // We can test the std::unique_ptr<> directly.
if (!value)
return false; // get() accesses the raw pointer underneath.
Foo* raw_ptr = foo_ptr.get(); // We can call through the std::unique_ptr<> as if it were a raw pointer.
DictionaryValue* dict;
if (!value->GetAsDictionary(&dict))
return false;

Why do we use them?

Smart pointers ensure we properly destroy an object even if its creation and destruction are widely separated. They make functions simpler and safer by ensuring that no matter how many different exit paths exist, local objects are always cleaned up correctly. They help enforce that exactly one object owns another object at any given time, preventing both leaks and double-frees. Finally, their use clarifies ownership transference expectations at function calls.

What types of smart pointers exist?

The two common smart pointers in Chromium are std::unique_ptr<> and scoped_refptr<>. The former is used for singly-owned objects, while the latter is used for reference-counted objects (though normally you should avoid these -- see below). If you're familiar with C++11, scoped_refptr<> is similar in intent to std::shared_ptr<>.

base/memory/ has a few other objects of interest:

  • linked_ptr<> is a deprecated object that was used mainly for storing smart pointers in containers pre-C++11. Now that Chromium supports C++11, you shouldn't use this; store std::unique_ptr<>s in containers directly (see below).
  • ScopedVector<> is also deprecated; this is a vector that owns the objects it contains. Use std::vector<std::unique_ptr<>> instead.
  • WeakPtr<> is not actually a smart pointer; it functions like a pointer type, but rather than being used to automatically free objects, it's used to track whether an object owned elsewhere is still alive. When the object is destroyed, the WeakPtr<> will be automatically set to null, so you can see that it's no longer alive. (You still need to test for null before dereferencing -- a blind dereference of a null WeakPtr<> is the equivalent of dereferencing null, rather than a no-op.) This is somewhat like C++11's std::weak_ptr<>, but with a different API and fewer restrictions.

When do we use each smart pointer?

  • Singly-owned objects - use std::unique_ptr<>. Specifically, these are for non-reference-counted, heap-allocated objects that you own.
  • Non-owned objects - use raw pointers or WeakPtr<>. Note that WeakPtr<>s must only be dereferenced on the same thread where they were created (usually by a WeakPtrFactory<>), and if you need to take some action immediately before or after an object is destroyed, you'd likely be better-served with some sort of callback or notification instead of a WeakPtr<>.
  • Ref-counted objects - use scoped_refptr<>, but better yet, rethink your design. Reference-counted objects make it difficult to understand ownership and destruction order, especially when multiple threads are involved. There is almost always another way to design your object hierarchy to avoid refcounting. Avoiding refcounting in multithreaded situations is usually easier if you restrict each class to operating on just one thread, and use PostTask() and the like to proxy calls to the correct thread. base::Bind()WeakPtr<>, and other tools make it possible to automatically cancel calls to such an object when it dies. Note that too much of our existing code uses refcounting, so just because you see existing code doing it does not mean it's the right solution. (Bonus points if you're able to clean up such cases.)
  • Platform-specific types - use one of the many platform-specific scoping objects, such as base::win::ScopedHandlebase::win::ScopedComPtr, or base::mac::ScopedCFTypeRef. Note that these may have slightly different usage patterns than std::unique_ptr<>; for example, they might be assigned as outparams via a .receive() type of method.

What are the calling conventions involving different kinds of pointers?

See the calling conventions section of the Chromium style guide for the rules; some common cases are illustrated below.

  • If a function takes a std::unique_ptr<>, that means it takes ownership of the argument. Callers need to use std::move() to indicate that they're passing ownership if the object being passed is not a temporary:

    // Foo() takes ownership of |bar|.
    void Foo(std::unique_ptr<Bar> bar); ...
    std::unique_ptr<Bar> bar_ptr(new Bar());
    Foo(std::move(bar_ptr)); // After this statement, |bar_ptr| is null.
    Foo(std::unique_ptr<Bar>(new Bar())); // No need to use std::move() on temporaries.
  • If a function returns a std::unique_ptr<>, that means the caller takes ownership of the returned object. Usage of std::move() while returning an object is only needed if the return type of the function differs from the type of the local variable.
    class Base { ... };
    class Derived : public Base { ... }; // Foo takes ownership of |base|, and the caller takes ownership of the returned
    // object.
    std::unique_ptr<Base> Foo(std::unique_ptr<Base> base) {
    if (cond) {
    return base; // Transfers ownership of |base| back to
    // the caller.
    } // Note that on these next codepaths, |base| is deleted on exit.
    if (cond2) {
    return std::unique_ptr<Base>(new Base())); // No std::move() necessary on temporaries.
    }
    std::unique_ptr<Derived> derived(new Derived());
    return std::move(derived); // Note that std::move() is necessary because
    // type of |derived| is different from the return
    // type of the function.
    }
  • If a function takes or returns a raw pointer, it may mean no ownership is transferred, or it may not. Much of Chromium was written before std::unique_ptr<> existed, or by people unfamiliar with using it to indicate ownership transfers, and thus takes or returns raw pointers but transfers ownership in the process. Because the compiler can't enforce correct behavior here, this is less safe. Consider cleaning up such code, so that functions which take or return raw pointers never transfer ownership.

What about passing or returning a smart pointer by reference?

Don't do this.

In principle, passing a const std::unique_ptr<T>& to a function which does not take ownership has some advantages over passing a T*: the caller can't accidentally pass in something utterly bogus (e.g. an int converted to a T*), and the caller is forced to guarantee the lifetime of the object persists across the function call. However, this declaration also forces callers to heap-allocate the objects in question, even if they could otherwise have declared them on the stack. Passing such arguments as raw pointers decouples the ownership issue from the allocation issue, so that the function is merely expressing a preference about the former. For the sake of simplicity and consistency, we avoid asking authors to balance these tradeoffs, and simply say to always use raw pointers.

One exception is lambda functions used with STL algorithms operating on containers of smart pointers; these may have to take e.g. const std::unique_ptr<T>& in order to compile. And speaking of that...

I want to use an STL container to hold pointers. Can I use smart pointers?

Yes! As of C++11, you can store smart pointers in STL containers. In particular, there's no longer a need to use ScopedVector<T>, since you can use std::vector<std::unique_ptr<T>> instead. Similarly, you should not use linked_ptr<T> anymore, since other smart pointers can now be stored in containers directly.

General references on smart pointers

Smart Pointer Guidelines的更多相关文章

  1. [CareerCup] 13.8 Smart Pointer 智能指针

    13.8 Write a smart pointer class. A smart pointer is a data type, usually implemented with templates ...

  2. 理解smart pointer之三:unique_ptr

    unique_ptr最先在boost中被定义,后来被C++标准委员会选中为C++11的feature之一. std::unique_ptr is a smart pointer that retain ...

  3. Why do we need smart pointer and how to implement it.

    Here are two simple questions. Problem A #include <string> include <iostream> using name ...

  4. c++ smart pointer

    智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露.它的一种通用实现技术是使用引用计数(reference ...

  5. c++(smart pointer)

    (一)首先对智能指针有一些概念性的了解 **********本部分内容摘自开源中国社区http://my.oschina.net/u/158589/blog/28994******** 1.什么是智能 ...

  6. c/c++ 标准库 智能指针( smart pointer ) 是啥玩意儿

    标准库 智能指针( smart pointer ) 是啥玩意儿 一,为什么有智能指针??? c++程序员需要自己善后自己动态开辟的内存,一旦忘了释放,内存就泄露. 智能指针可以帮助程序员"自 ...

  7. C++ smart pointer智能指针

      在C++中,程序员可以直接操作内存,给编程增加了不少的灵活性.但是灵活性是有代价的,程序员必须负责自己负责释放自己申请的内存,否则就会出现内存泄露.智能指针就是为了解决这个问题而存在的.它和其他指 ...

  8. Effective C++ Item 17 Store newed objects in smart pointer in standalone statements

    If you trying to do multiple things in one statement, you should think carefully abnormal behavior e ...

  9. Smart pointer 智能指针小总结

    Smart pointer line 58之后smart pointer里的计数已经是0,所以会真正释放它引用的对象,调用被引用对象的析构函数.如果继续用指针访问,会出现如下图的内存访问异常.所以说如 ...

随机推荐

  1. 【BZOJ 1503】[NOI2004]郁闷的出纳员

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 因为所有人工资同时递减. 所以可以设置一个变化值delta. 然后每个人的初始值为k 则把k-delta加入伸展树中. 会发现del ...

  2. 最强最全干货分享:Android开发书籍、教程、工具等

    最全干货分享,本文收集整理了Android开发所需的书籍.教程.工具.资讯和周刊各种资源,它们能让你在Android开发之旅的各个阶段都受益. 入门<Learning Android(中文版)& ...

  3. Redit集群搭建-Sentinel模式搭建

    Redit集群搭建 学习了: Windows:http://blog.csdn.net/mrxiagc/article/details/52799081 Linux:https://www.cnblo ...

  4. how to deal with &quot;no such file error or diretory&quot; error for a new programmer in QT creator

    when i try to develop a hello demo in QT creator with the code following : #include<QApplication& ...

  5. PHP第九课 正則表達式在PHP中的使用

    今天内容 1.正則表達式 2.数学函数 3.日期函数 4.错误处理 正則表達式: 1.模式修正符 2.五个经常使用函数 另外一个正則表達式的站点:http://www.jb51.net/tools/z ...

  6. MYSQL学习笔记三:日期和时间函数

    MYSQL学习笔记三:日期和时间函数 1. 获取当前日期的函数和获取当前时间的函数 /*获取当前日期的函数和获取当前时间的函数.将日期以'YYYY-MM-DD'或者'YYYYMMDD'格式返回 */ ...

  7. NSURLCache、网络监測状态

    有时候.对同一个URL请求多次.返回的数据可能一样的: 比方server上的某张图片.不管下载多少次,返回的数据都是一样的.可是这些情况会造成下面问题: 1,用户流量的浪费. 2.程序响应速度不够快 ...

  8. poj_1195Mobile phones,二维树状数组

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> us ...

  9. Laravel-自定全局函数

    Laravel-自定全局函数 标签(空格分隔): php 习惯了 使用 ThinkPHP 框架,有一个公共方法类在代码编写上会快捷很多,所以有必要在此进行配置一番. 实现 在 app 创建文件夹 He ...

  10. 机器学习(七) PCA与梯度上升法 (下)

    五.高维数据映射为低维数据 换一个坐标轴.在新的坐标轴里面表示原来高维的数据. 低维 反向 映射为高维数据 PCA.py import numpy as np class PCA: def __ini ...