借助c++11智能指针,因为智能指针可以自定义删除器,在智能指针释放的时候会调用删除器,在删除器中我们将用完的对象重新放回对象池。
思路比较简单,但实现的时候需要考虑两个问题:
1,什么时候定义删除器?
2,用shared_ptr
还是unique_ptr
?
1111111111111111111111111,什么时候定义删除器
自定义删除器只做一件事,就是将对象重新放入对象池。
如果对象池初始化的时候就自定义删除器的话,删除器中的逻辑是将对象放回对象池,
放回的时候无法再定义一个这样的删除器,所以这种做法行不通。需要注意,回收的
对象只能是默认删除器的。
只有在get
的时候定义删除器才行,但是初始创建或加入的智能指针是默认删除器,
所以我们需要把智能指针的默认删除器改为自定义删除器。
222222222222222222222222222222,用shared_ptr
还是unique_ptr
因为我们需要把智能指针的默认删除器改为自定义删除器,用shared_ptr
会很不方便,因
为你无法直接将shared_ptr
的删除器修改为自定义删除器,虽然你可以通过重新创建一个新
对象,把原对象拷贝过来的做法来实现,但是这样做效率比较低。
而unique_ptr
由于是独占语义,提供了一种简便的方法方法可以实现修改删除器,所以用unique_ptr
是最适合的。
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
#pragma once
#include <memory>
#include <vector>
#include <functional>
template <class T>
class SimpleObjectPool
{
public:
using DeleterType = std::function<void(T*)>;
void add(std::unique_ptr<T> t)
{
pool_.push_back(std::move(t));
}
std::unique_ptr<T, DeleterType> get()
{
if (pool_.empty())
{
throw std::logic_error("no more object");
}
//every time add custom deleter for default unique_ptr
std::unique_ptr<T, DeleterType> ptr(pool_.back().release(), [this](T* t)
{
pool_.push_back(std::unique_ptr<T>(t));
});
pool_.pop_back();
return std::move(ptr);
}
bool empty() const
{
return pool_.empty();
}
size_t size() const
{
return pool_.size();
}
private:
std::vector<std::unique_ptr<T>> pool_;
};
//test code
void test_object_pool()
{
SimpleObjectPool<A> p;
p.add(std::unique_ptr<A>(new A()));
p.add(std::unique_ptr<A>(new A()));
{
auto t = p.get();
p.get();
}
{
p.get();
p.get();
}
std::cout << p.size() << std::endl;
}
如果你坚持用
shared_ptr
,那么回收的时候你需要这样写:
std::shared_ptr<T> get()
{
if (pool_.empty())
{
throw std::logic_error("no more object");
}
std::shared_ptr<T> ptr = pool_.back();
auto p = std::shared_ptr<T>(new T(std::move(*ptr.get())), [this](T* t)
{
pool_.push_back(std::shared_ptr<T>(t));
});
//std::unique_ptr<T, DeleterType> ptr(pool_.back().release(), [this](T* t)
//{
// pool_.push_back(std::unique_ptr<T>(t));
//});
pool_.pop_back();
return p;
}
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
shared_ptr是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的引用计数(reference counting)。
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
shared_ptr基本用法
shared_ptr采用引用计数的方式管理所指向的对象。当有一个新的shared_ptr指向同一个对象时(复制shared_ptr等),引用计数加1。当shared_ptr离开作用域时,引用计数减1。当引用计数为0时,释放所管理的内存。
这样做的好处在于解放了程序员手动释放内存的压力。之前,为了处理程序中的异常情况,往往需要将指针手动封装到类中,通过析构函数来释放动态分配的内存;现在这一过程就可以交给shared_ptr去做了。
一般我们使用make_shared来获得shared_ptr。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
cout<<
"test shared_ptr base usage:"
<<endl;
shared_ptr<string> p1 = make_shared<string>(
""
);
if
(p1 && p1->empty())
*p1 =
"hello"
;
auto p2 = make_shared<string>(
"world"
);
cout<<*p1<<
' '
<<*p2<<endl;
cout<<
"test shared_ptr use_count:"
<<endl;
cout<<
"p1 cnt:"
<<p1.use_count()<<
"\tp2 cnt:"
<<p2.use_count()<<endl;
auto p3 = p2;
cout<<
"p1 cnt:"
<<p1.use_count()<<
"\tp2 cnt:"
<<p2.use_count()<<
"\tp3 cnt:"
<<p3.use_count()<<endl;
p2 = p1;
cout<<
"p1 cnt:"
<<p1.use_count()<<
"\tp2 cnt:"
<<p2.use_count()<<
"\tp3 cnt:"
<<p3.use_count()<<endl;
|
shared_ptr和new
shared_ptr可以使用一个new表达式返回的指针进行初始化。
1
2
3
4
|
cout<<
"test shared_ptr and new:"
<<endl;
shared_ptr<
int
> p4(
new
int
(1024));
//shared_ptr<int> p5 = new int(1024); // wrong, no implicit constructor
cout<<*p4<<endl;
|
但是,不能将一个new表达式返回的指针赋值给shared_ptr。
另外,特别需要注意的是,不要混用new和shared_ptr!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
void
process(shared_ptr<
int
> ptr)
{
cout<<
"in process use_count:"
<<ptr.use_count()<<endl;
}
cout<<
"don't mix shared_ptr and normal pointer:"
<<endl;
shared_ptr<
int
> p5(
new
int
(1024));
process(p5);
int
v5 = *p5;
cout<<
"v5: "
<<v5<<endl;
int
*p6 =
new
int
(1024);
process(shared_ptr<
int
>(p6));
int
v6 = *p6;
cout<<
"v6: "
<<v6<<endl;
|
上面的程序片段会输出:
in process use_count:2
v5: 1024
in process use_count:1
v6: 0
可以看到,第二次process p6时,shared_ptr的引用计数为1,当离开process的作用域时,会释放对应的内存,此时p6成为了悬挂指针。
所以,一旦将一个new表达式返回的指针交由shared_ptr管理之后,就不要再通过普通指针访问这块内存!
shared_ptr.reset
shared_ptr可以通过reset方法重置指向另一个对象,此时原对象的引用计数减一。
1
2
3
4
5
|
cout<<
"test shared_ptr reset:"
<<endl;
cout<<
"p1 cnt:"
<<p1.use_count()<<
"\tp2 cnt:"
<<p2.use_count()<<
"\tp3 nt:"
<<p3.use_count()<<endl;
p1.reset(
new
string(
"cpp11"
));
cout<<
"p1 cnt:"
<<p1.use_count()<<
"\tp2 cnt:"
<<p2.use_count()<<
"\tp3 cnt:"
<<p3.use_count()<<endl;
shared_ptr deleter
|
可以定制一个deleter函数,用于在shared_ptr释放对象时调用。
1
2
3
4
5
6
7
8
9
10
|
void
print_at_delete(
int
*p)
{
cout<<
"deleting..."
<<p<<
'\t'
<<*p<<endl;
delete
p;
}
cout<<
"test shared_ptr deleter:"
<<endl;
int
*p7 =
new
int
(1024);
shared_ptr<
int
> p8(p7, print_at_delete);
p8 = make_shared<
int
>(1025);
|
unique_ptr基本用法
unique_ptr对于所指向的对象,正如其名
字所示,是 独占 的。所以,不可以对
unique_ptr进行拷贝、赋值等操作,但是
可以通过release函数在unique_ptr之间转
移控制权。
1
2
3
4
5
6
7
8
9
10
|
cout<<
"test unique_ptr base usage:"
<<endl;
unique_ptr<
int
> up1(
new
int
(1024));
cout<<
"up1: "
<<*up1<<endl;
unique_ptr<
int
> up2(up1.release());
cout<<
"up2: "
<<*up2<<endl;
//unique_ptr<int> up3(up1); // wrong, unique_ptr can not copy
//up2 = up1; // wrong, unique_ptr can not copy
unique_ptr<
int
> up4(
new
int
(1025));
up4.reset(up2.release());
cout<<
"up4: "
<<*up4<<endl;
|
unique_ptr作为参数和返回值
上述对于拷贝的限制,有两个特殊情况,即unique_ptr可以作为函数的返回值和参数使用,这时虽然也有隐含的拷贝存在,但是并非不可行的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
unique_ptr<
int
> clone(
int
p)
{
return
unique_ptr<
int
>(
new
int
(p));
}
void
process_unique_ptr(unique_ptr<
int
> up)
{
cout<<
"process unique ptr: "
<<*up<<endl;
}
cout<<
"test unique_ptr parameter and return value:"
<<endl;
auto up5 = clone(1024);
cout<<
"up5: "
<<*up5<<endl;
process_unique_ptr(move(up5));
//cout<<"up5 after process: "<<*up5<<endl; // would cause segmentfault
|
这里的std::move函数,以后再单独具体细说^_^
unique_ptr deleter
unique_ptr同样可以设置deleter,和shared_ptr不同的是,它需要在模板参数中指定deleter的类型。好在我们有decltype这个利器,不然写起来好麻烦。
1
2
3
4
5
|
cout<<
"test unique_ptr deleter:"
<<endl;
int
*p9 =
new
int
(1024);
unique_ptr<
int
, decltype(print_at_delete) *> up6(p9, print_at_delete);
unique_ptr<
int
> up7(
new
int
(1025));
up6.reset(up7.release());
|
weak_ptr
weak_ptr一般和shared_ptr配合使用。它可以指向shared_ptr所指向的对象,但是却不增加对象的引用计数。这样就有可能出现weak_ptr所指向的对象实际上已经被释放了的情况。因此,weak_ptr有一个lock函数,尝试取回一个指向对象的shared_ptr。
1
2
3
4
5
6
7
|
cout<<
"test weak_ptr basic usage:"
<<endl;
auto p10 = make_shared<
int
>(1024);
weak_ptr<
int
> wp1(p10);
cout<<
"p10 use_count: "
<<p10.use_count()<<endl;
//p10.reset(new int(1025)); // this will cause wp1.lock() return a false obj
shared_ptr<
int
> p11 = wp1.lock();
if
(p11) cout<<
"wp1: "
<<*p11<<
" use count: "
<<p11.use_count()<<endl;
|
总结
shared_ptr采用引用计数的方式管理所指向的对象。
shared_ptr可以使用一个new表达式返回的指针进行初始化;但是,不能将一个new表达式返回的指针赋值给shared_ptr。
一旦将一个new表达式返回的指针交由shared_ptr管理之后,就不要再通过普通指针访问这块内存。
shared_ptr可以通过reset方法重置指向另一个对象,此时原对象的引用计数减一。
可以定制一个deleter函数,用于在shared_ptr释放对象时调用。
unique_ptr对于所指向的对象,是独占的。
不可以对unique_ptr进行拷贝、赋值等操作,但是可以通过release函数在unique_ptr之间转移控制权。
unique_ptr可以作为函数的返回值和参数使用。
unique_ptr同样可以设置deleter,需要在模板参数中指定deleter的类型。
weak_ptr一般和shared_ptr配合使用。它可以指向shared_ptr所指向的对象,但是却不增加对象的引用计数。
weak_ptr有一个lock函数,尝试取回一个指向对象的shared_ptr。
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
C++中的智能指针首先出现在“准”标准库boost中。随着使用的人越来越多,为了让开发人员更方便、更安全的使用动态内存,C++11也引入了智能指针来管理动态对象。在新标准中,主要提供了shared_ptr、unique_ptr、weak_ptr三种不同类型的智能指针。接下来的几篇文章,我们就来总结一下这些智能指针的使用。
今天,我们先来看看shared_ptr智能指针。
shared_ptr
shared_ptr是一个引用计数智能指针,用于共享对象的所有权也就是说它允许多个指针指向同一个对象。这一点与原始指针一致。
先来一段简单的代码,看看shared_ptr的简单使用:
#include <iostream>
#include <memory>
using namespace std;
class Example
{
public:
Example() : e(1) { cout << "Example Constructor..." << endl; }
~Example() { cout << "Example Destructor..." << endl; }
int e;
};
int main() {
shared_ptr<Example> pInt(new Example());
cout << (*pInt).e << endl;
cout << "pInt引用计数: " << pInt.use_count() << endl;
shared_ptr<Example> pInt2 = pInt;
cout << "pInt引用计数: " << pInt.use_count() << endl;
cout << "pInt2引用计数: " << pInt2.use_count() << endl;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
程序输出如下:
Example Constructor...
pInt: 1
pInt引用计数: 1
pInt引用计数: 2
pInt2引用计数: 2
Example Destructor...
- 1
- 2
- 3
- 4
- 5
- 6
从上面这段代码中,我们对shared_ptr指针有了一些直观的了解。一方面,跟STL中大多数容器类型一样,shared_ptr也是模板类,因此在创建shared_ptr时需要指定其指向的类型。另一方面,正如其名一样,shared_ptr指针允许让多个该类型的指针共享同一堆分配对象。同时shared_ptr使用经典的“引用计数”方法来管理对象资源,每个shared_ptr对象关联一个共享的引用计数。对于“引用计数”的问题,这里就不展开介绍。有兴趣的同学可以上网查找资料,或者看看我的另一篇文章 【Cocos2d-x源码分析】 Cocos2d-x内存管理解析(Cocos2d-x也使用了“引用计数”方法来实现内存管理)。
对于shared_ptr在拷贝和赋值时的行为,《C++Primer第五版》中有详细的描述:
每个shared_ptr都有一个关联的计数值,通常称为引用计数。无论何时我们拷贝一个shared_ptr,计数器都会递增。
例如,当用一个shared_ptr初始化另一个shred_ptr,或将它当做参数传递给一个函数以及作为函数的返回值时,它
所关联的计数器就会递增。当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的
shared_ptr离开其作用域)时,计数器就会递减。一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理
的对象。
- 1
- 2
- 3
- 4
- 5
对比我们上面的代码可以看到:当我们将一个指向Example对象的指针交给pInt管理后,其关联的引用计数为1。接下来,我们用pInt初始化pInt2,两者关联的引用计数值增加为2。随后,函数结束,pInt和PInt2相继离开函数作用于,相应的引用计数值分别自减1最后变为0,于是Example对象被自动释放(调用其析构函数)。
接下来,我们完整地介绍一下shared_ptr的常见用法:
1、创建shared_ptr实例
最安全和高效的方法是调用make_shared库函数,该函数会在堆中分配一个对象并初始化,最后返回指向此对象的share_ptr实例。如果你不想使用make_ptr,也可以先明确new出一个对象,然后把其原始指针传递给share_ptr的构造函数。
示例如下:
int main() {
// 传递给make_shared函数的参数必须和shared_ptr所指向类型的某个构造函数相匹配
shared_ptr<string> pStr = make_shared<string>(10, 'a');
cout << *pStr << endl; // aaaaaaaaaa
int *p = new int(5);
shared_ptr<int> pInt(p);
cout << *pInt << endl; // 5
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
2、访问所指对象
shared_ptr的使用方式与普通指针的使用方式类似,既可以使用解引用操作符*获得原始对象进而访问其各个成员,也可以使用指针访问符->来访问原始对象的各个成员。
3、拷贝和赋值操作
我们可以用一个shared_ptr对象来初始化另一个share_ptr实例,该操作会增加其引用计数值。
例如:
int main() {
shared_ptr<string> pStr = make_shared<string>(10, 'a');
cout << pStr.use_count() << endl; // 1
shared_ptr<string> pStr2(pStr);
cout << pStr.use_count() << endl; // 2
cout << pStr2.use_count() << endl; // 2
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
如果shared_ptr实例p和另一个shared_ptr实例q所指向的类型相同或者可以相互转换,我们还可以进行诸如p = q这样赋值操作。该操作会递减p的引用计数值,递增q的引用计数值。
例如:
class Example
{
public:
Example(string n) : name(n) { cout << n << " constructor..." << endl; }
~Example() { cout << name << " destructor..." << endl; }
string name;
};
int main() {
shared_ptr<Example> pStr = make_shared<Example>("a object");
shared_ptr<Example> pStr2 = make_shared<Example>("b object");
cout << pStr.use_count() << endl;
cout << pStr2.use_count() << endl;
pStr = pStr2; // 此后pStr和pStr指向相同对象
cout << pStr->name << endl;
cout << pStr2->name << endl;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
输出如下:
a object constructor...
b object constructor...
1
1
a object destructor...
b object
b object
b object destructor...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
4、检查引用计数
shared_ptr提供了两个函数来检查其共享的引用计数值,分别是unique()和use_count()。
在前面,我们已经多次使用过use_count()函数,该函数返回当前指针的引用计数值。值得注意的是use_count()函数可能效率很低,应该只把它用于测试或调试。
unique()函数用来测试该shared_ptr是否是原始指针唯一拥有者,也就是use_count()的返回值为1时返回true,否则返回false。
示例:
int main() {
shared_ptr<string> pStr = make_shared<string>(10, 'a');
cout << pStr.unique() << endl; // true
shared_ptr<string> pStr2(pStr);
cout << pStr2.unique() << endl; // false;
}
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
在前面一篇文章中,我们了解了C++11中引入的智能指针之一shared_ptr,今天,我们来介绍一下另一种智能指针unique_ptr。
unique_ptr介绍
unique是独特的、唯一的意思,故名思议,unique_ptr可以“独占”地拥有它所指向的对象,它提供一种严格意义上的所有权。这一点和我们前面介绍的shared_ptr类型指针有很大的不同:shared_ptr允许多个
指针指向同一对象,而unique_ptr在某一
时刻只能有一个指针指向该对象。unique_ptr保存指向某个对象的指针,当它本身被删除或者离开其作用域时会自动释放其指向对象所占用的资源。
下面,我们就来具体介绍一下unique_ptr的基本特性。
1、如何创建unique_ptr
unique_ptr不像shared_ptr一样拥有标准库函数make_shared来创建一个shared_ptr实例。要想创建一个unique_ptr,我们需要将一个new 操作符返回的指针传递给unique_ptr的构造函数。
示例:
int main() {
// 创建一个unique_ptr实例
unique_ptr<int> pInt(new int(5));
cout << *pInt;
}
- 1
- 2
- 3
- 4
- 5
2、无法进行复制构造和赋值操作
unique_ptr没有copy构造函数,不支持普通的拷贝和赋值操作。
int main() {
// 创建一个unique_ptr实例
unique_ptr<int> pInt(new int(5));
unique_ptr<int> pInt2(pInt); // 报错
unique_ptr<int> pInt3 = pInt; // 报错
}
- 1
- 2
- 3
- 4
- 5
- 6
3、可以进行移动构造和移动赋值操作
unique_ptr虽然没有支持普通的拷贝和赋值操作,但却提供了一种移动机制来将指针的所有权从一个unique_ptr转移给另一个unique_ptr。如果需要转移所有权,可以使用std::move()函数。
示例:
int main() {
unique_ptr<int> pInt(new int(5));
unique_ptr<int> pInt2 = std::move(pInt); // 转移所有权
//cout << *pInt << endl; // 出错,pInt为空
cout << *pInt2 << endl;
unique_ptr<int> pInt3(std::move(pInt2));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
4、可以返回unique_ptr
unique_ptr不支持拷贝操作,但却有一个例外:可以从函数中返回一个unique_ptr。
示例:
unique_ptr<int> clone(int p)
{
unique_ptr<int> pInt(new int(p));
return pInt; // 返回unique_ptr
}
int main() {
int p = 5;
unique_ptr<int> ret = clone(p);
cout << *ret << endl;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
unique_ptr使用场景
1、为动态申请的资源提供异常安全保证
我们先来看看下面这一段代码:
void Func()
{
int *p = new int(5);
// ...(可能会抛出异常)
delete p;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
这是我们传统的写法:当我们动态申请内存后,有可能我们接下来的代码由于抛出异常或者提前退出(if语句)而没有执行delete操作。
解决的方法是使用unique_ptr来管理动态内存,只要unique_ptr指针创建成功,其析构函数都会被调用。确保动态资源被释放。
void Func()
{
unique_ptr<int> p(new int(5));
// ...(可能会抛出异常)
}
- 1
- 2
- 3
- 4
- 5
- 6
2、返回函数内动态申请资源的所有权
unique_ptr<int> Func(int p)
{
unique_ptr<int> pInt(new int(p));
return pInt; // 返回unique_ptr
}
int main() {
int p = 5;
unique_ptr<int> ret = Func(p);
cout << *ret << endl;
// 函数结束后,自动释放资源
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
3、在容器中保存指针
int main() {
vector<unique_ptr<int>> vec;
unique_ptr<int> p(new int(5));
vec.push_back(std::move(p)); // 使用移动语义
}
- 1
- 2
- 3
- 4
- 5
4、管理动态数组
标准库提供了一个可以管理动态数组的unique_ptr版本。
int main() {
unique_ptr<int[]> p(new int[5] {1, 2, 3, 4, 5});
p[0] = 0; // 重载了operator[]
}
- 1
- 2
- 3
- 4