uniqut_ptr是一种对资源具有排他性拥有权的智能指针,即一个对象资源只能同时被一个unique_ptr指向。

一、初始化方式

  1. 通过new云算法或者普通指针

unique_ptr<Investment> up(new Investment());

或者

Investment *pInv = new Investment();

unique_ptr<Investment> up1(pInv);

  1. 通过make_unique

auto pInv = make_unique<Investment>();

  1. 通过move()函数

    unique_ptr<Investment> up1 = std::move(up);

注意:unique_ptr不能被复制或者拷贝,下面的代码将出错:

unique_ptr<Investment> up(new Investment()); //ok

unique_ptr<Investment> up1(up);              //error, can not be copy

unique_ptr<Investment> up2 = up;            //error, can not be assigned

但是,unique_ptr可以作为函数的返回值:

unique_ptr<Investment> GetPtr();        //function getthe unique pointer

unique_ptr<Investment> pInv = GetPtr(); // ok

二、自定义释放器

用如下方式使用带自定义资源释放的unique_ptr

auto delete_Investment = [](Investment* pInv)

{

pInv->getObjectType();

delete pInv;

};

unique_ptr<Investment,decltype(delete_Investment)> pInvest(nullptr,delete_Investment);

或者也可以使用函数指针

void deleteInv(Investment* pInv) {}

std::unique_ptr<Investment,void(*)(Investment*)>ptr(nullptr,deleteInv) ;

三、 unique_ptr 基本操作

unique_ptr<Investment> pInvestment;     // 创建一个空的智能指针

pInvestment.reset(new Investment());    //"绑定”动态对象

Investment *pI = pInvestment.release(); //释放所有权

pI= nullptr;                         //显式销毁所指对象,同时智能指针变为空指针。

四、管理动态数组

由于unique_ptr有std::unique_ptr<T[]>的重载函数,所以它可以用来管理数组资源

unique_ptr<int[]> pArray(new int[3]{1,3,3});

在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。

动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极其困难的。有时会忘记释放内存,在这种情况下会产生内存泄露;有时在尚有指针引用内存的情况下就释放了它,在这种情况下就会产生引用非法内存的指针。

为了更容易(同时也更安全)地使用动态内存,C++11标准库提供了两种智能指针(smart pointer)类型来管理动态对象。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指的对象。C++11标准库提供的这两种智能指针的区别在于管理底层指针的方式:shared_ptr允许多个指针指向同一个对象;unique_ptr则"独占"所指向的对象。C++11标准库还定义了一个名为weak_ptr的辅助类,它是一种弱引用,指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。智能指针是模板类而不是指针。类似vector,智能指针也是模板,当创建一个智能指针时,必须提供额外的信息即指针可以指向的类型。默认初始化的智能指针中保存着一个空指针。智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。如果在一个条件判断中使用智能指针,效果就是检测它是否为空。

In C++, a smart pointer is implemented as a template class that mimics, by means of operator overloading, the behaviors of a traditional (raw) pointer, (e.g. dereferencing, assignment) while providing additional memory management features.

std::unique_ptr is a smart pointer that retains sole ownership of an object through a pointer and destroys that object when the unique_ptr goes out of scope. No two unique_ptr instances can manage the same object.

The object is destroyed and its memory deallocated when either of the following happens: (1)、the managing unique_ptr object is destroyed; (2)、the managing unique_ptr object is assigned another pointer via operator= or reset().

A unique_ptr may alternatively own no object, in which case it is called empty.

Only non-const unique_ptr can transfer the ownership of the managed object to another unique_ptr. The lifetime of an object managed by const std::unique_ptr is limited to the scope in which the pointer was created.

std::unique_ptr may be constructed for an incomplete type T. Conversely, std::shared_ptr can't be constructed from a raw pointer to incomplete type, but can be destroyed where T is incomplete.

A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr, passed by value to a function, or used in any Standard Template Library (STL) algorithm that requires copies to be made. A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it.

When using unique_ptr, there can be at most one unique_ptr pointing at any one resource.When that unique_ptr is destroyed, the resource is automatically reclaimed.Because there can only be one unique_ptr to any resource, any attempt to make a copy of a unique_ptr will cause a compile-time error. However, unique_ptr can be moved using the new move semantics.

shared_ptr, allows for multiple pointers to point at a given resource. When the very last shared_ptr to a resource is destroyed, the resource will be deallocated. shared_ptr uses reference counting to track how many pointers refer to a resource, so you need to be careful not to introduce any reference cycles.

A unique_ptr is a container for a raw pointer, which the unique_ptr is said to own. A unique_ptr explicitly prevents copying of its contained pointer (as would happen with normal assignment), but the std::move function can be used to transfer ownership of the contained pointer to another unique_ptr. A unique_ptr cannot be copied because its copy constructor and assignment operators are explicitly deleted.

everything you can do with auto_ptr, unique_ptr will do as well.

There are two kinds of unique_ptr, one for scalars (i.e. non-arrays) and one for arrays:

(1)、unique_ptr<double> can hold a scalar of type double;

(2)、unique_ptr<double[]> can hold an array of double values with an unknown number of elements.

std::unique_ptr是C++11标准中用来取代std::auto_ptr的指针容器(在C++11中,auto_ptr被废弃)。它不能与其它unique_ptr类型的指针对象共享所指对象的内存。这种”所有权”仅能够通过标准库的move函数来转移。unique_ptr是一个删除了拷贝构造函数、保留了移动构造函数的指针封装类型。

一个unique_ptr"拥有"它所指向的对象。与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象。当unique_ptr被销毁时,它所指向的对象也被销毁。与shared_ptr不同,在C++11中,没有类似make_shared的标准库函数返回一个unique_ptr。当定义一个unique_ptr时,需要将其绑定到一个new返回的指针上。类似shared_ptr,初始化unique_ptr必须采用直接初始化形式。由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作。虽然不能拷贝或赋值unique_ptr,但可以通过调用release或reset将指针的所有权从一个(非const)unique_ptr转移给另一个unique。

调用release会切断unique_ptr和它原来管理的对象间的联系。release返回的指针通过被用来初始化另一个智能指针或给另一个智能指针赋值。如果不用另一个智能指针来保存release返回的指针,程序就要负责资源的释放。

不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr,最常见的例子是从函数返回一个unique_ptr。

类似shared_ptr,unique_ptr默认情况下用delete释放它指向的对象。与shared_ptr一样,可以重载一个unique_ptr中默认的删除器。但是,unique_ptr管理删除器的方式与shared_ptr不同。

下图列出了unique_ptr支持的操作(来源于C++ Primer Fifth Edition 中文版):

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "unique_ptr.hpp"
#include <iostream>
#include <memory>
#include <string>
#include <cstdlib>
#include <utility>
#include <vector>
#include <algorithm>
#include <cassert>
#include <fstream>
#include <functional> namespace unique_ptr_ { ///////////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/memory/unique_ptr
struct Foo
{
Foo() { std::cout << "Foo::Foo\n"; }
~Foo() { std::cout << "Foo::~Foo\n"; }
void bar() { std::cout << "Foo::bar\n"; }
}; void f(const Foo &)
{
std::cout << "f(const Foo&)\n";
} int test_unique_ptr1()
{
std::unique_ptr<Foo> p1(new Foo); // p1 owns Foo
if (p1) p1->bar(); {
std::unique_ptr<Foo> p2(std::move(p1)); // now p2 owns Foo
f(*p2); p1 = std::move(p2); // ownership returns to p1
std::cout << "destroying p2...\n";
} if (p1) p1->bar(); // Foo instance is destroyed when p1 goes out of scope return ;
} //////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/memory/unique_ptr/unique_ptr/
int test_unique_ptr2()
{
std::default_delete<int> d;
std::unique_ptr<int> u1;
std::unique_ptr<int> u2(nullptr);
std::unique_ptr<int> u3(new int);
std::unique_ptr<int> u4(new int, d);
std::unique_ptr<int> u5(new int, std::default_delete<int>());
std::unique_ptr<int> u6(std::move(u5));
std::unique_ptr<int> u7(std::move(u6));
std::unique_ptr<int> u8(std::auto_ptr<int>(new int)); std::cout << "u1: " << (u1 ? "not null" : "null") << '\n';
std::cout << "u2: " << (u2 ? "not null" : "null") << '\n';
std::cout << "u3: " << (u3 ? "not null" : "null") << '\n';
std::cout << "u4: " << (u4 ? "not null" : "null") << '\n';
std::cout << "u5: " << (u5 ? "not null" : "null") << '\n';
std::cout << "u6: " << (u6 ? "not null" : "null") << '\n';
std::cout << "u7: " << (u7 ? "not null" : "null") << '\n';
std::cout << "u8: " << (u8 ? "not null" : "null") << '\n'; return ;
} //////////////////////////////////////////////////////
// reference: http://eli.thegreenplace.net/2012/06/20/c11-using-unique_ptr-with-standard-library-containers
struct Foo_0 {
Foo_0() { std::cerr << "Foo_0 [" << this << "] constructed\n"; }
virtual ~Foo_0() { std::cerr << "Foo_0 [" << this << "] destructed\n"; }
}; void sink(std::unique_ptr<Foo_0> p) {
std::cerr << "Sink owns Foo_0 [" << p.get() << "]\n";
} std::unique_ptr<Foo_0> source() {
std::cerr << "Creating Foo_0 in source\n";
return std::unique_ptr<Foo_0>(new Foo_0);
} int test_unique_ptr3()
{
std::cerr << "Calling source\n";
std::unique_ptr<Foo_0> pmain = source(); // Can also be written as
// auto pmain = source(); std::cerr << "Now pmain owns Foo [" << pmain.get() << "]\n";
std::cerr << "Passing it to sink\n";
// sink(pmain); // ERROR! can't copy unique_ptr
sink(move(pmain)); // OK: can move it! std::cerr << "Main done\n";
return ;
} ////////////////////////////////////////////////////
// reference: http://www.codeguru.com/cpp/article.php/c17775/The-Smart-Pointer-That-Makes-Your-C-Applications-Safer--stduniqueptr.htm
void func(int*)
{ } int test_unique_ptr4()
{
// default construction
std::unique_ptr<int> up; //creates an empty object // initialize with an argument
std::unique_ptr<int> uptr(new int());
double *pd = new double;
std::unique_ptr<double> uptr2(pd);
// overloaded * and ->
*uptr2 = 23.5;
std::unique_ptr<std::string> ups(new std::string("hello"));
int len = ups->size(); // Reset() releases the owned resource and optionally acquires a new resource:
uptr2.reset(new double); //delete pd and acquire a new pointer
uptr2.reset(); //delete the pointer acquired by the previous reset() call // If you need to access the owned pointer directly use get()
func(uptr.get()); // Unique_ptr has implicit conversion to bool.
// This lets you use unique_ptr object in Boolean expressions such as this:
if (ups) //implicit conversion to bool
std::cout << *ups << std::endl;
else
std::cout << "an empty smart pointer" << std::endl; // Array Support: Unique_ptr can store arrays as well.
// A unique_ptr that owns an array defines an overloaded operator [].
// Obviously, the * and -> operators are not available.
// Additionally, the default deleter calls delete[] instead of delete:
std::unique_ptr<int[]> arrup(new int[]);
arrup[] = ;
// std::cout << *arrup << std::endl; //error, operator * not defined // Compatibility with Containers and Algorithms
// You can safely store unique_ptr in Standard Library containers and let algorithms manipulate sequences of unique_ptr objects.
std::vector<std::unique_ptr<int>> vi;
vi.push_back(std::unique_ptr<int>(new int())); // populate vector
vi.push_back(std::unique_ptr<int>(new int()));
vi.push_back(std::unique_ptr<int>(new int()));
std::sort(vi.begin(), vi.end()); // result: {0, 2, 3} return ;
} //////////////////////////////////////////////////////////////////
template <typename T>
class Add {
public:
T add_sub(T a, T b)
{
return (a + b) * (a - b);
}
}; int test_unique_ptr5()
{
std::unique_ptr<Add<int>> tt(new Add<int>());
int a{ }, b{ }; std::cout << tt->add_sub(a, b) << std::endl; return ;
} //////////////////////////////////////////////////////////////////
int test_unique_ptr6()
{
std::unique_ptr<int[]> tmp(new int[]);
std::for_each(tmp.get(), tmp.get() + , [](int& n) {n = ; });
std::cout << tmp[] << std::endl; return ;
} ///////////////////////////////////////////////////////////////////////
// reference: https://en.cppreference.com/w/cpp/memory/unique_ptr
struct B {
virtual void bar() { std::cout << "B::bar\n"; }
virtual ~B() = default;
};
struct D : B
{
D() { std::cout << "D::D\n"; }
~D() { std::cout << "D::~D\n"; }
void bar() override { std::cout << "D::bar\n"; }
}; // a function consuming a unique_ptr can take it by value or by rvalue reference
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
p->bar();
return p;
} void close_file(std::FILE* fp) { std::fclose(fp); } int test_unique_ptr7()
{
std::cout << "unique ownership semantics demo\n";
{
auto p = std::make_unique<D>(); // p is a unique_ptr that owns a D
auto q = pass_through(std::move(p));
assert(!p); // now p owns nothing and holds a null pointer
q->bar(); // and q owns the D object
} // ~D called here std::cout << "Runtime polymorphism demo\n";
{
std::unique_ptr<B> p = std::make_unique<D>(); // p is a unique_ptr that owns a D
// as a pointer to base
p->bar(); // virtual dispatch std::vector<std::unique_ptr<B>> v; // unique_ptr can be stored in a container
v.push_back(std::make_unique<D>());
v.push_back(std::move(p));
v.emplace_back(new D);
for (auto& p : v) p->bar(); // virtual dispatch
} // ~D called 3 times std::cout << "Custom deleter demo\n";
std::ofstream("demo.txt") << 'x'; // prepare the file to read
{
std::unique_ptr<std::FILE, decltype(&close_file)> fp(std::fopen("demo.txt", "r"), &close_file);
if (fp) // fopen could have failed; in which case fp holds a null pointer
std::cout << (char)std::fgetc(fp.get()) << '\n';
} // fclose() called here, but only if FILE* is not a null pointer
// (that is, if fopen succeeded) std::cout << "Custom lambda-expression deleter demo\n";
{
std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr)
{
std::cout << "destroying from a custom deleter...\n";
delete ptr;
}); // p owns D
p->bar();
} // the lambda above is called and D is destroyed std::cout << "Array form of unique_ptr demo\n";
{
std::unique_ptr<D[]> p{ new D[] };
} // calls ~D 3 times return ;
} /////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/memory/unique_ptr/~unique_ptr/
int test_unique_ptr8()
{
auto deleter = [](int*p){
delete p;
std::cout << "[deleter called]\n";
}; std::unique_ptr<int, decltype(deleter)> foo(new int, deleter); std::cout << "foo " << (foo ? "is not" : "is") << " empty\n"; return ; // [deleter called]
} /////////////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/memory/unique_ptr/get_deleter/
class state_deleter { // a deleter class with state
int count_;
public:
state_deleter() : count_() {}
template <class T>
void operator()(T* p) {
std::cout << "[deleted #" << ++count_ << "]\n";
delete p;
}
}; int test_unique_ptr9()
{
state_deleter del; std::unique_ptr<int> p; // uses default deleter // alpha and beta use independent copies of the deleter:
std::unique_ptr<int, state_deleter> alpha(new int);
std::unique_ptr<int, state_deleter> beta(new int, alpha.get_deleter()); // gamma and delta share the deleter "del" (deleter type is a reference!):
std::unique_ptr<int, state_deleter&> gamma(new int, del);
std::unique_ptr<int, state_deleter&> delta(new int, gamma.get_deleter()); std::cout << "resetting alpha..."; alpha.reset(new int);
std::cout << "resetting beta..."; beta.reset(new int);
std::cout << "resetting gamma..."; gamma.reset(new int);
std::cout << "resetting delta..."; delta.reset(new int); std::cout << "calling gamma/delta deleter...";
gamma.get_deleter()(new int); alpha.get_deleter() = state_deleter(); // a brand new deleter for alpha // additional deletions when unique_ptr objects reach out of scope
// (in inverse order of declaration) return ;
} //////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/
int test_unique_ptr10()
{
std::unique_ptr<int> foo;
std::unique_ptr<int> bar; foo = std::unique_ptr<int>(new int()); // rvalue bar = std::move(foo); // using std::move std::cout << "foo: ";
if (foo) std::cout << *foo << '\n'; else std::cout << "empty\n"; std::cout << "bar: ";
if (bar) std::cout << *bar << '\n'; else std::cout << "empty\n"; return ;
} /////////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/memory/unique_ptr/release/
int test_unique_ptr11()
{
std::unique_ptr<int> auto_pointer(new int);
int * manual_pointer; *auto_pointer = ; manual_pointer = auto_pointer.release();
// (auto_pointer is now empty) std::cout << "manual_pointer points to " << *manual_pointer << '\n'; delete manual_pointer; return ; } ///////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/memory/unique_ptr/swap/
int test_unique_ptr12()
{
std::unique_ptr<int> foo(new int()), foo2(new int());
std::unique_ptr<int> bar(new int()), bar2(new int()); foo.swap(bar);
std::cout << "foo: " << *foo << '\n';
std::cout << "bar: " << *bar << '\n'; std::swap(foo2, bar2);
std::cout << "foo2: " << *foo2 << '\n';
std::cout << "bar2: " << *bar2 << '\n'; return ;
} ////////////////////////////////////////////////////////////////
void math_add(int* a)
{
int b = ++(*a);
delete a;
fprintf(stdout, "add operation: %d\n", b);
} void math_subtract(int* a)
{
int b = --(*a);
delete a;
fprintf(stdout, "subtraction operation: %d\n", b);
} int test_unique_ptr13()
{
{
std::unique_ptr<int, decltype(&math_add)> A(new int, &math_add);
if (!A) {
fprintf(stderr, "A is nullptr\n");
return -;
} *A = ;
} {
typedef std::unique_ptr<int, std::function<void(int*)>> Oper; Oper A(new int, math_add);
*A = ; Oper B(new int, math_subtract);
*B = ;
} return ;
} } // namespace unique_ptr_

C++11智能指针之std::unique_ptr的更多相关文章

  1. 智能指针(1)-std::unique_ptr

    std::unique_ptr std::unique_ptr是一种几乎和原始指针一样高效的智能指针,对所管理的指针资源拥有独占权.由C++11标准引入,用于替代C++98中过时的std::auto_ ...

  2. c++11 智能指针 unique_ptr、shared_ptr与weak_ptr

    c++11 智能指针 unique_ptr.shared_ptr与weak_ptr C++11中有unique_ptr.shared_ptr与weak_ptr等智能指针(smart pointer), ...

  3. C++11——智能指针

    1. 介绍 一般一个程序在内存中可以大体划分为三部分——静态内存(局部的static对象.类static数据成员以及所有定义在函数或者类之外的变量).栈内存(保存和定义在函数或者类内部的变量)和动态内 ...

  4. 详解C++11智能指针

    前言 C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用. C++11智能指针介 ...

  5. C++11智能指针读书笔记;

    智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...

  6. 【C++11新特性】 C++11智能指针之weak_ptr

    如题,我们今天要讲的是C++11引入的三种智能指针中的最后一个:weak_ptr.在学习weak_ptr之前最好对shared_ptr有所了解.如果你还不知道shared_ptr是何物,可以看看我的另 ...

  7. C++11智能指针 share_ptr,unique_ptr,weak_ptr用法

    0x01  智能指针简介  所谓智能指针(smart pointer)就是智能/自动化的管理指针所指向的动态资源的释放.它是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动 ...

  8. C++11 新特性之智能指针(shared_ptr, unique_ptr, weak_ptr)

    这是C++11新特性介绍的第五部分,涉及到智能指针的相关内容(shared_ptr, unique_ptr, weak_ptr). shared_ptr shared_ptr 基本用法 shared_ ...

  9. C++11 智能指针unique_ptr使用 -- 以排序二叉树为例

    用智能指针可以简化内存管理.以树为例,如果用普通指针,通常是在插入新节点时用new,在析构函数中调用delete:但有了unique_ptr类型的智能指针,就不需要在析构函数中delete了,因为当u ...

随机推荐

  1. 微信小程序~性能

    (1)优化建议 setData setData 是小程序开发中使用最频繁的接口,也是最容易引发性能问题的接口.在介绍常见的错误用法前,先简单介绍一下 setData 背后的工作原理. 工作原理 小程序 ...

  2. test20190815 NOIP2019 模拟题

    100+60+40=200,被后面两个题卡着我很不爽. 立方数 [问题描述] 作为 XX 战队的狂热粉丝,MdZzZZ 看到了自己心仪的队伍在半决赛落败,顿时 心灰意冷.看着自己手中的从黄牛那里抢来的 ...

  3. machine learning (1)

    Machine learning (1)   机器学习的两种定义 the field of study that gives computers the ability to learn withou ...

  4. linux第一天命令

    命令 :   命令 [选项] [参数]   /;根目录 用户主目录:/home/用户名   <==>  ~   1.ls 显示路径中的内容   ls [参数] [路径] ls ls -l  ...

  5. BAT文件的调用

    分成2个步骤,首先生成一个bat文件,然后调用批处理文件 1.生成.bat文件 入参为文件的内容,filePath为绝对路径,且需要扩展名(这个方法不局限于生成.bat文件,也可以生成其他扩展名文件) ...

  6. pdfminer批量处理PDF文件

    from pdfminer.pdfparser import PDFParser, PDFDocument from pdfminer.pdfinterp import PDFResourceMana ...

  7. flask入门脚本解释

    创建一个最小的flask应用, 稍做编辑如下, 开启debug调试模式后, 服务器自动加载服务器的修改. 如何自己构建一个优雅的url呢 http方法介绍 http访问urls的方法有get, pos ...

  8. (1)React的开发

    1.React项目架构搭建 2.JSX语法 3.React组件化开发 4.React组件间通信 5.React中的事件 6.React代码优化 7.React中组件的样式修饰 React简介及基础语法 ...

  9. Python 全栈开发【第0篇】:目录

    Python 全栈开发[第0篇]:目录   第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基 ...

  10. Java RabbitMQ配置和使用,基于SpringBoot

    package rabbitmq.demo; import com.rabbitmq.client.AMQP; import org.junit.Test; import org.junit.runn ...