左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式)。需要注意的是,左值是指表达式结束后依然存在的持久对象,而右值是指表达式结束时就不再存在的临时对象。T& 指向的是 lvalue,而 const T& 指向的,却可能是 lvalue 或 rvalue,左值引用&与右值引用&&(右值引用是c++11加上的)。
需要明确的是,move函数可以是用于构造函数,也可以用于赋值函数,但都需要手动显示添加。其实**move函数用直白点的话来说就是省去拷贝构造和赋值时中间的临时对象,**将资源的内存从一个对象移动到(共享也可以)另一个对象。 官话是:c++11 中的 move() 是这样一个函数,它接受一个参数,然后返回一个该参数对应的右值引用。
std::forward<T>(u)有两个参数:T 与 u。当T为左值引用类型时,u将被转换为T类型的左值,否则u将被转换为T类型右值。如此定义std::forward是为了在使用右值引用参数的函数模板中解决参数的完美转发问题。 意思就是:把右值的对象(right)移动给左值(_myt&),并且右值清空。
unique_ptr中的拷贝构造和赋值操作符delete了,所以也就意味着,他和auto_ptr有区别,控制权唯一,不能随意转换。用法都差不多
#include "stdafx.h" #include <iostream> #include <memory> using namespace std; class Base{ }; int _tmain(int argc, _TCHAR* argv[]) { unique_ptr<Base> baseUnique(new Base); cout <<"baseUnique.get() = "<< baseUnique.get()<<endl; unique_ptr<Base> baseUnique2=move(baseUnique); cout << "move(baseUnique)已执行"<< endl; cout << "baseUnique.get() = " << baseUnique.get() << endl; cout << "baseUnique2.get() = " << baseUnique2.get() << endl; return 0; }输出
baseUnique.get() = 0097F7C0 move(baseUnique)已执行 baseUnique.get() = 00000000 baseUnique2.get() = 0097F7C0前者控制权唯一,切换的时候把前面的清除。而shared_ptr不会,很显然,可以直接赋值和调用拷贝构造函数,且不会清空原本的智能指针。 有个地方需要注意,当删除一个智能指针时,并不影响其它两个智能指针的继续使用。因为该片内存添加了一个引用计数,每shared_ptr一次,引用计数+1;每次调用析构函数,引用计数减一。直到最后一个智能指针删除,才会释放内存。 (其实auto_ptr也有,只是一样,没必要截图了)也就是说,auto_ptr和unique_ptr都可以通过move函数转换成shared_ptr类型,当然,一样是切换控制权的形式,即旧的置空。
#include "stdafx.h" #include <iostream> #include <memory> using namespace std; class Base{ }; int _tmain(int argc, _TCHAR* argv[]) { cout << "####unique_ptr####" << endl; unique_ptr<Base> baseUnique(new Base); cout <<"baseUnique.get() = "<< baseUnique.get()<<endl; unique_ptr<Base> baseUnique2=move(baseUnique); cout << "move(baseUnique)已执行"<< endl; cout << "baseUnique.get() = " << baseUnique.get() << endl; cout << "baseUnique2.get() = " << baseUnique2.get() << endl; cout << "####shared_ptr####" << endl; shared_ptr<Base> baseShared(new Base); cout << "当前引用次数:" << baseShared.use_count() << endl; shared_ptr<Base> baseShared2 = baseShared; cout << "执行shared_ptr<Base> baseShared2 = baseShared;\n当前baseShared引用次数:" << baseShared.use_count() << endl; shared_ptr<Base> baseShared3 = move(baseShared); cout << "执行shared_ptr<Base> baseShared3 = move(baseShared);\n当前baseShared引用次数:" << baseShared.use_count() << endl; cout << "当前baseShared3引用次数:" << baseShared3.use_count() << endl; return 0; }输出
baseUnique.get() = 0097F7C0 move(baseUnique)已执行 baseUnique.get() = 00000000 baseUnique2.get() = 0097F7C0weak_ptr本身也是一个模板类, 但是不能直接用它来定义一个智能指针的对象,只能配合shared_ptr来使用,可以将shared_ptr的对象赋值给weak_ptr,并且这样并不会改变引用计数的值。查看weak_ptr的代码时发现,它主要有lock、swap、reset、expired、operator=、use_count几个函数,与shared_ptr相比多了lock、expired函数,但是却少了get函数
解决这种状况的办法就是将两个类中的一个成员变量改为weak_ptr对象,因为weak_ptr不会增加引用计数,使得引用形不成环,最后就可以正常的释放内部的对象,不会造成内存泄漏