已经有成千上万的文章讨论这个问题,所以我只想说:现在能使用的,带引用计数,并且能自动释放内存的智能
指针包括一下几种:
a、unique_ptr:如果内存资源的所有权不需要共享,就应当使用这个(它没有拷贝构造函数),但是它可以转让
给另一个unique_ptr(存在move构造函数)。
b、share_ptr:如果内存资源需要共享,那么使用这个。
c、weak_ptr:持有被shared_ptr所管理对象的引用,但是不会改变引用计数值,它被用来打破依赖循环(想象在
一个tree结构中,父节点通过一个共享所有权的引用(shared_ptr)引用子节点,同时子节点又必须持有父节点的
引用。如果这第二个引用也共享所有权,就会导致一个循环,最终导致两个节点内存都无法释放)
另一方面,auto_ptr已经被废弃,不会再使用了。
什么时候使用unique_ptr,什么时候使用shared_ptr取决于所有权的需求,我建议阅读以下讨论:
http://stackoverflow.com/questions/15648844/using-smart-pointers-for-class-members
一下第一个例子使用了unique_ptr。如果你想把对象所有权转移给另一个unique_ptr,需要使用std::move。在所有权
转移后,交出所有权的智能指针为空,get()函数将返回nullptr。
void foo(int *p)
{
std::cout<<*p<<std::endl;
}
std::unique_ptr<int> p1(new int(42));
std::unique_ptr<int> p2 = std::move(p1);
//transfer ownership
if(p1)
foo(p1.get());
(*p2)++;
if(p2)
foo(p2.get());
第二处例子展示了shared_ptr。用法相似,但语义不同,此时所有权是共享的。
void foo(int* p)
{
std::cout<<*p<<std::endl;
}
void bar(std::shared_ptr<int> p)
{
++(*p);
}
std::shared_ptr<int> p1(new int(42));
std::shared_ptr<int> p2 = p1;
bar(p1);
foo(p2.get());
第一个声明和以下这行是等价的:
auto p3 = std::make_shared<int>(42);
make_shared<T>是一个非成员函数,使用它的好处是可以一次性分配共享对象和智能指针自身的内存。而显示地使用
shared_ptr构造函数来构造则至少需要两次内存分配。除了会产生额外的开销,还可能会导致内存泄漏。在下面这个例子
中,如果seed()抛出一个错误就会产生内存泄漏。
void foo(std::shared_ptr<int> p,int init)
{
*p = init;
}
foo(std::shared_ptr<int>(new int(42)),seed());
如果使用make_shared就不会有这个问题了。第三个例子展示了weak_ptr。注意,你必须调用lock()来获得被引用对象的
shared_ptr,通过它才能访问这个对象。
auto p = std::make_shared<int>(42);
std::weak_ptr<int> wp = p;
{
auto sp = wp.lock();
std::cout<<*sp<<std::endl;
}
p.reset();
if(wp.expired())
std::cout<<"expired"<<std::endl;
如果试图锁定(lock)一个过期(指被弱引用对象已经被释放)的weak_ptr,那你将获得一个空 的shared_ptr.
7、Lambdas
在标准C++,特别是当使用C++标准程序库算法函数诸如sort和find,用户经常希望能够在算法函数调用的附近定义
一个临时的述部函数(又称谓词函数,predicate function)。由于语言本身允许在函数内部定义类型,可以考虑使用
函数对象,然而这通常既麻烦又冗赘,也阻碍了代码的流程,此外标准C++不允许定义于函数内部的类型被用于模板,所
以前述的作法是不可行的。
C++11对lambda的支持可以解决上述问题
一个lambda函数可以用如下的方式定义:
[](int x,int y){return x+y;}
这个不具名函数返回类型是decltype(x+y)。只有在lambda函数符合"return expression"的形式下,它的回返类型
才能被忽略。在前述的情况下,lambda函数仅能为一个述句。
在一个更为复杂的例子中,回返类型可以被明确的指定如下:
[](int x,int y)->int{int z = x+y; return z+x;}
本例中,一个暂时的变量z被创建用来存储中间结果。如同一般的函数,z的值不会保留到一下次该不具名函数再次被
调用时。
如果lambda函数没有返回值(例如void),其回返类型可以被完全忽略。定义在与lambda函数相同作用域的变量参考
也可以被使用。这种的变量集合一般称作closure(闭包)。
[] //没有定义任何参数。使用未定义参数会导致错误
[x,&y] //x以传值方式传入(预设),y以传引用方式传入。
[&] //任何被使用到的外部参数皆隐式地以引用方式加以使用。
[=] //任何被使用到的外部参数皆隐式地以传值方式加以使用
[&,x] //x显示地以传值方式加以使用,其余参数以引用方式加以使用
[=,&z] //z显示地以传引用的方式加以使用。其余参数以传参数方式加以使用。