智能指针的使用及注意事项

1.为什么要使用智能指针?

opencv中对为什么使用智能指针的说法阐述得非常好
-Default constructor, copy constructor, and assignment operator for an arbitrary C++ class or C structure. For some objects, like files, windows, mutexes, sockets, and others, a copy constructor or an assignment operator are difficult to define. For some other objects, like complex classifiers in OpenCV, copy constructors are absent and not easy to implement. Finally, some of complex OpenCV and your own data structures may be written in C. However, copy constructors and default constructors can simplify programming a lot. Besides, they are often required (for example, by STL containers). By using a Ptr to such an object instead of the object itself, you automatically get all of the necessary constructors and the assignment operator.
- O(1) complexity of the above-mentioned operations. While some structures, like std::vector, provide a copy constructor and an assignment operator, the operations may take a considerable
amount of time if the data structures are large. But if the structures are put into a Ptr, the overhead is small and independent of the data size.
- Automatic and customizable cleanup, even for C structures.
- Heterogeneous collections of objects. The standard STL and most other C++ and OpenCV containers can store only objects of the same type and the same size. The classical solution to store
objects of different types in the same container is to store pointers to the base class (Base*) instead but then you lose the automatic memory management. Again, by using Ptr instead
of raw pointers, you can solve the problem.
@note The shared ownership mechanism is implemented with reference counting. As such, cyclic
ownership (e.g. when object a contains a Ptr to object b, which contains a Ptr to object a) will
lead to all involved objects never being cleaned up. Avoid such situations.
@note It is safe to concurrently read (but not write) a Ptr instance from multiple threads and
therefore it is normally safe to use it in multi-threaded applications. The same is true for Mat and
other C++ OpenCV classes that use internal reference counts.
好处总的来说就是:
(1)自动释放内存
(2)方便使用STL容器

2.智能指针shared_ptr基本用法

直接上代码

#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;

int main()
{
    // two shared pointers representing two persons by their name
    //shared_ptr<string> pNico(new string("nico"));
    shared_ptr<string> pNico{new string("nico")};
//    shared_ptr<string> pNico;
//    pNico.reset(new string("nico"));

    shared_ptr<string> pJutta(new string("jutta"));

    // capitalize person names
    (*pNico)[0] = 'N';
    pJutta->replace(0,1,"J");

    // put them multiple times in a container
    vector<shared_ptr<string>> whoMadeCoffee;
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pNico);
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pNico);

    // print all elements
    for (auto ptr : whoMadeCoffee) {
        cout << *ptr << "  ";
    }
    cout << endl;

    // overwrite a name again
    *pNico = "Nicolai";

    // print all elements again
    for (auto ptr : whoMadeCoffee) {
        cout << *ptr << "  ";
    }
    cout << endl;

    // print some internal data
    cout << "use_count: " << whoMadeCoffee[0].use_count() << endl;
    return 0;
}

注意,编译的时候加上add_definitions(-g -std=c++11)使用c++11
新建智能指针的方法
(1)shared_ptr pNico(new string(“nico”));
(2)shared_ptr pNico{new string(“nico”)};
(3)使用reset
shared_ptr pNico4;
pNico4.reset(new string(“nico”));
(4)使用make_shared(“nico”)推荐
最后能够调用use_count()来输出引用数目.
注意,使用智能指针不要手动调用delete,系统会在use_count()=0自动释放内存.

3智能指针shared_ptr使用总结

shared_ptr的使用总结:
(1)若要在内部传递this,请考虑从enable_shared_from_this继承
若从enable_shared_from_this继承,则类对象必须让shared_ptr接管,使用enable_shared_from_this机制来把this从类内部传递出来。
(2)如果要使用智能指针,那么就要保持一致,统统使用智能智能,尽量减少raw pointer裸指针的使用。
(3)C++没有垃圾收集,资源管理需要自己来做。智能指针可以部分解决资源管理的工作,但是不是万能的。
(4)使用智能指针的时候,每个shared_ptr对象都应该有一个名字;也就是避免在一个表达式内做多个资源的初始化;
(5)避免shared_ptr的交叉引用;使用weak_ptr打破交叉;
(6)资源管理保持统一风格,要么使用智能指针,要么就全部自己管理裸指针;

4智能指针weak_ptr使用

#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;

class Person {
  public:
    string name;
    Person (const string& n)   : name(n) {  cout<<"create person"<<n<<endl;}
    ~Person() {
      cout << "delete " << name << endl;
    }
};
int main()
{
    vector<shared_ptr<Person>> vPersons(3,nullptr);
    shared_ptr<Person> mom(new Person(" mom"));
   cout<<"1mom.use_count()"<<mom.use_count()<<endl;
    vPersons[0]=mom;
    cout<<"2 mom.use_count()"<<mom.use_count()<<endl;
    vector<weak_ptr<Person> > vPerson;
    weak_ptr<Person> wmom(mom);
    vPerson.push_back(wmom);
    cout<<"3 mom.use_count()"<<mom.use_count()<<endl;
    cout<<"4 wmom.use_count()"<<wmom.use_count()<<endl;

    vector<shared_ptr<Person> > vPerson2;
    vPerson2.push_back(wmom.lock());

    cout<<"6 mom.use_count()"<<mom.use_count()<<endl;
    cout<<"5 wmom.use_count()"<<wmom.use_count()<<endl;
}

(1)shared_ptr使用一次,引用计数就加一次
(2)weak_ptr使用一次,引用计数不增加
(3)查看weak_ptr的引用计数,就是对应的shared_ptr 的引用计数
(4)weak_ptr.lock()返回一个shared_ptr,如果返回的shared_ptr被使用,引用计数增加

3智能指针unique_ptr使用

#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;

class Person {
  public:
    string name;
    Person (const string& n)   : name(n) {  cout<<"create person"<<n<<endl;}
    ~Person() {
      cout << "delete " << name << endl;
    }
};
void UsePerson(unique_ptr< Person>person)
{

}
unique_ptr< Person>  ReturnPerson(unique_ptr< Person>person)
{
     return person;
}
int main()
{
    //1create way1
    unique_ptr<Person> pNico(new Person("nico"));
    //2create way2
    unique_ptr<Person> pJack(new Person("jack"));

    unique_ptr<Person> pLucy(new Person("lucy"));

    //3delete using reset or =nullptr
    //pNico.reset();
    pNico=nullptr;
    //4.error use!!
    //UsePerson(pJack);
    //5.person will be delete
    UsePerson(std::move(pJack));
    if(nullptr==pJack)
    {
        cout<<"jack dead"<<endl;
    }
    //6.return person
    unique_ptr<Person> rLucy=ReturnPerson(move(pLucy));

    // 7.replaced nico
    pLucy.reset(new Person("logon"));
    return 0;
}

(1)新建用new新建,注意不能用等号
unique_ptr pNico(new string(“nico”));
(2)使用reset或=nullptr删除,此时会调用析构函数
(3)使用move()转移对象的拥有权
(4)当unique_ptr作为函数参数时要加move()操作,否则无法使用
(5)返回一个unique_ptr时,系统会自动加 move()操作
(6)使用reset(new),删除原来对象,并设置为新的对象.
pLucy.reset(new Person(“logon”));
删除了lucy对象,设置pLucy指向logon对象.

猜你喜欢

转载自blog.csdn.net/ktigerhero3/article/details/80135662