ПОДРОБНОЕ C ++ 11 смарт-указатель

предисловие

Внутри четырех C ++ смарт-указатель: auto_ptr, unique_ptr, shared_ptr, weak_ptr где три является C ++ поддерживает 11, 11 и первая была отброшена C ++.

C ++ 11 вводит смарт-указатель

Интеллектуальные указатели в основном используются для управления памятью в куче, это общий пакет объект указателя стека. Когда в конце жизненного цикла стека объектов, приложение будет освобождено в деструкторе памяти, чтобы предотвратить утечку памяти. C ++ 11 наиболее часто используемым является shared_ptr смарт-тип указателя, который использует метод подсчета ссылок, номер текущей записи ссылочные ресурсы памяти смарт-указатель. Счетчик ссылок выделяется на память кучи. Плюс 1, уменьшает счетчик ссылок, когда новый, когда истекает счетчик ссылок. Только тогда, когда счетчик ссылок 0, смарт-указатель будет автоматически освободить ссылку на ресурс памяти. Вы не можете назначить обычный указатель при инициализации непосредственно shared_ptr смарт-указатель, как указатель, класс есть. Она может передаваться через обычный указатель make_shared конструктор или функцию. А может быть получена с помощью обычной функции указатель ГЭТ.

Зачем использовать смарт-указатель

Роль интеллектуального указателя является управлением указателем, потому что есть такой случай: применение космической техники забудьте выпустить в конце функции, что приводит к утечке памяти. Использование смарт-указатели могут в значительной степени избежать этой проблемы, потому что умный указатель класса, когда класс выходит за рамки этого класса будет автоматически вызывать деструктор, деструктор будет автоматически освободить ресурсы. Таким образом, роль принципа смарт-указатель автоматически освободить пространство памяти в конце функции, без необходимости вручную освободить место в памяти.

auto_ptr

(C ++ 98 программ, C ++ 11 отказались), используя собственный режим.

auto_ptr<string> p1 (new string ("I reigned lonely as a cloud.”)); 
auto_ptr<string> p2; 
p2 = p1; //auto_ptr不会报错.

На данный момент не жалуется, p2, лишенные собственности p1, p1, но доступ будет сгенерировано при запуске программы. Так auto_ptr недостаток заключается в том: есть потенциальная проблема повреждения памяти!

unique_ptr

(Заменить auto_ptr) unique_ptr осуществлять строгий владеет или имеет эксклюзивные концепции, убедитесь, что только один умный указатель может указывать на объект в то же время. Крайне важно, чтобы избежать утечки ресурсов (например, «После создания новых объектов, так как происходит исключение и забудьте вызвать удаление») особенно полезен.

Примеры использования формы собственности или выше

unique_ptr<string> p3 (new string ("auto"));   //#4
unique_ptr<string> p4;                       //#5
p4 = p3;//此时会报错!!

Компилятор думаю p4 = p3 незаконно, избегая проблем, р3 больше не указывают на достоверных данных. Это будет ошибка компиляции при попытке скопировать p3, и auto_ptr может составить ошибку, которая похоронена скрытая опасность во время выполнения. Поэтому unique_ptr более безопасным, чем auto_ptr.

Кроме того, есть более умные места unique_ptr: Когда программа пытается unique_ptr приписана к другому, если источник является временным unique_ptr правильных значений, компилятор позволил сделать это, если источник unique_ptr будет существовать в течение некоторого времени, то компилятор будет запрещено делать так, Например:

unique_ptr<string> pu1(new string ("hello world")); 
unique_ptr<string> pu2; 
pu2 = pu1;                                      // #1 不允许
unique_ptr<string> pu3; 
pu3 = unique_ptr<string>(new string ("You"));   // #2 允许

Где # 1 повис unique_ptr (PU1), что может привести к причинению вреда. И # 2 не оставит висит unique_ptr, как это называет конструктор unique_ptr, конструктор создает временные объекты будут уничтожены после того, как его собственности дают Ри3. Такая ситуация с поведением на шоу, unique_ptr, чем позволить auto_ptr два задания.

Примечание: Если вы действительно хотите , чтобы выполнить операцию , аналогичную # 1, чтобы обеспечить повторное использование таких указателей можно присвоить ей новое значение. Существует стандарт C ++ библиотека функций станд :: перемещать (), позволяет назначить unique_ptr другой. Несмотря на передачу права собственности по - прежнему можно первоначальными вызовы указателя ситуации (звонки разрушаться) появляется. Но грамматика вы можете подчеркнуть передачу права собственности, так что вы четко знаете , что они делают, чтобы не вызвать хаос оригинальный указатель.

( Дополнительно: подпиточного :: scoped_ptr библиотеки Boost , является эксклюзивным смарт - указатель, но он не позволяет передачу права собственности от начала и до конца только отвечает за ресурс, он является более безопасным , осторожным, но и более узкий диапазон применения.)

Например:

unique_ptr<string> ps1, ps2;
ps1 = demo("hello");
ps2 = move(ps1);
ps1 = demo("alexia");
cout << *ps2 << *ps1 << endl;

shared_ptr

shared_ptr должны достичь общей концепции. Несколько умных указатели могут указывать на тот же объект и связанные с ним ресурсы «будет уничтожены последней ссылка» при отпускании. Доля может быть видна из названия ресурса может совместно использоваться несколькими указателями, используя механизм подсчета, чтобы указать, что ресурсы распределяются несколько указателей. Вы можете увидеть номер владельца ресурса с помощью функции-члена use_count (). Кроме того, чтобы быть построен новый, может быть построена путем пропускания auto_ptr, unique_ptr, weak_ptr. Когда мы называем отпустить (), текущий указатель будет освободить ресурсы собственности, рассчитывать на один. Когда счетчик равен 0, то ресурс освобождается.

shared_ptr является устранение ограничений на владение объекта auto_ptr (auto_ptr является исключительным), предоставляет интеллектуальный указатель на долю владения в механизме использует подсчет ссылок.

Функция пользователя:

Возвращает номер подсчета ссылок use_count

Уникальные, возвращает ли исключительный владелец (use_count 1)

для замены двух объектов shared_ptr (то есть объекты, принадлежащие обмена)

Сокращение внутреннего сброса отказаться от права собственности на объект или объект изменился, то это вызовет счетчик ссылок исходного объекта

Возвращает внутренние получают объекты (указатели), потому что у них есть метод тяжелой нагрузки (), и поэтому прямое использование объекта такого же, как

shared_ptr<int> sp(new int(1)); 

зр и sp.get () эквивалентны.

share_ptr простой пример:

int main()
{
    string *s1 = new string("s1");

    shared_ptr<string> ps1(s1);
    shared_ptr<string> ps2;
    ps2 = ps1;

    cout << ps1.use_count()<<endl;  //2
    cout<<ps2.use_count()<<endl;    //2
    cout << ps1.unique()<<endl; //0

    string *s3 = new string("s3");
    shared_ptr<string> ps3(s3);

    cout << (ps1.get()) << endl;    //033AEB48
    cout << ps3.get() << endl;  //033B2C50
    swap(ps1, ps3); //交换所拥有的对象
    cout << (ps1.get())<<endl;  //033B2C50
    cout << ps3.get() << endl;  //033AEB48

    cout << ps1.use_count()<<endl;  //1
    cout << ps2.use_count() << endl;    //2
    ps2 = ps1;
    cout << ps1.use_count()<<endl;  //2
    cout << ps2.use_count() << endl;    //2
    ps1.reset();    //放弃ps1的拥有权,引用计数的减少
    cout << ps1.use_count()<<endl;  //0
    cout << ps2.use_count()<<endl;  //1
}

weak_ptr

share_ptr Хотя это было хорошо проведено, но одно share_ptr смарт-указатель все еще есть случай утечки памяти, когда два объекта друг с другом, используя переменную, указывающую член shared_ptr друг на друга, приведет к циклической ссылки, неудачи подсчета ссылок, в результате утечки памяти.

weak_ptr не контролируем является смарт-объект указатель жизненного цикла, он указывает на объект, управляемый shared_ptr управления памятью. объекта, на который ссылается сильным shared_ptr, weak_ptr только обеспечивает средство доступа к управляемым объектам. Weak_ptr цель разработан с смарт-указатель вводятся, чтобы помочь shared_ptr shared_ptr работы, это может быть только от одного или другого объекта строительства weak_ptr shared_ptr, его конструкция и деструктор не вызывают увеличение числа референтной метки или уменьшаются. weak_ptr используется для решения тупиковой ситуации, когда shared_ptr ссылаются друг на друга, если два shared_ptr ссылаются друг на друга, то два указателя счетчик ссылок никогда не упадет до 0, ресурс никогда не освобождается. Это является слабой ссылкой на объект, объект не будет увеличивать счетчик ссылок между ними, и может быть преобразован друг в друг shared_ptr, shared_ptr может быть назначен непосредственно к нему, он может быть получен путем вызова функции блокировки shared_ptr.

class B;    //声明
class A
{
public:
    shared_ptr<B> pb_;
    ~A()
    {
        cout << "A delete\n";
    }
};

class B
{
public:
    shared_ptr<A> pa_;
    ~B()
    {
        cout << "B delete\n";
    }
};

void fun()
{
    shared_ptr<B> pb(new B());
    shared_ptr<A> pa(new A());
    cout << pb.use_count() << endl; //1
    cout << pa.use_count() << endl; //1
    pb->pa_ = pa;
    pa->pb_ = pb;
    cout << pb.use_count() << endl; //2
    cout << pa.use_count() << endl; //2
}

int main()
{
    fun();
    return 0;
}

См прикольных функцию ра, ссылки друг на друга пб, два ресурса счетчик ссылок 2, когда переход к функции, смарт-указатель ра, рь деструктор, когда два ресурса счетчик ссылок уменьшается на единицу, но и цитируемые или для подсчета 1, в результате чего ресурсы не будут освобождены (а, в не деструктор будет называться) не работает из вывода контента результаты функции деструктора, что приводит к утечке памяти. Если один вместо weak_ptr на него, мы помещаем внутри класса А shared_ptr Pb_, вместо weak_ptr Pb_, результаты выглядят следующим образом:

1
1
1
2
B delete
A delete

В этом случае, ссылка на ресурс Б 1 начинается только тогда, когда пб деструктор, счетчик становится B 0, B высвобождается, а также сделать выделение B минус количество 1, в то время, когда Деструктор ра рассчитывать на 1, счетчик а является 0, то высвобождается.

Примечание: мы не можем weak_ptr прямого доступа к методу объекта, объект B , таким как метод Print (), поэтому мы не можем доступ, па-> рь _-> Печать ( ), так как Pb_ weak_ptr, он должен первое преобразование а shared_ptr , такие как:

shared_ptr<B> p = pa->pb_.lock();
p->print();

Ядро share_ptr и weak_ptr реализация

weakptr слабый указатель ссылки, которая зависит от реализации счетчика и присвоения класса счетчика share_ptr, конфигурации, и таким образом, первый счетчика share_ptr

Счетчик простой реализации

class Counter
{
public:
    Counter() : s(0), w(0){};
    int s;  //share_ptr的引用计数
    int w;  //weak_ptr的引用计数
};

голова к прилавку объекта используются для применения куска памяти, чтобы сохранить базовую ссылку, с share_ptr это счетчик ссылок, счетчик ссылок weak_ptr из ш, когда ш 0, объект удаления счетчика.

Простая реализация share_ptr

template <class T>
class WeakPtr; //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用

template <class T>
class SharePtr
{
public:
    SharePtr(T *p = 0) : _ptr(p)
    {
        cnt = new Counter();
        if (p)
            cnt->s = 1;
        cout << "in construct " << cnt->s << endl;
    }
    ~SharePtr()
    {
        release();
    }

    SharePtr(SharePtr<T> const &s)
    {
        cout << "in copy con" << endl;
        _ptr = s._ptr;
        (s.cnt)->s++;
        cout << "copy construct" << (s.cnt)->s << endl;
        cnt = s.cnt;
    }
    SharePtr(WeakPtr<T> const &w) //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用
    {
        cout << "in w copy con " << endl;
        _ptr = w._ptr;
        (w.cnt)->s++;
        cout << "copy w  construct" << (w.cnt)->s << endl;
        cnt = w.cnt;
    }
    SharePtr<T> &operator=(SharePtr<T> &s)
    {
        if (this != &s)
        {
            release();
            (s.cnt)->s++;
            cout << "assign construct " << (s.cnt)->s << endl;
            cnt = s.cnt;
            _ptr = s._ptr;
        }
        return *this;
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }
    friend class WeakPtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值

protected:
    void release()
    {
        cnt->s--;
        cout << "release " << cnt->s << endl;
        if (cnt->s < 1)
        {
            delete _ptr;
            if (cnt->w < 1)
            {
                delete cnt;
                cnt = NULL;
            }
        }
    }

private:
    T *_ptr;
    Counter *cnt;
};

Share_ptr заданной функции интерфейса, как: конфигурации, конструктор копирование, назначение разыменования, выпуск и удалять _ptr CNT памяти равно 0, когда счетчик ссылок.

weak_ptr простой реализации

template <class T>
class WeakPtr
{
public: //给出默认构造和拷贝构造,其中拷贝构造不能有从原始指针进行构造
    WeakPtr()
    {
        _ptr = 0;
        cnt = 0;
    }
    WeakPtr(SharePtr<T> &s) : _ptr(s._ptr), cnt(s.cnt)
    {
        cout << "w con s" << endl;
        cnt->w++;
    }
    WeakPtr(WeakPtr<T> &w) : _ptr(w._ptr), cnt(w.cnt)
    {
        cnt->w++;
    }
    ~WeakPtr()
    {
        release();
    }
    WeakPtr<T> &operator=(WeakPtr<T> &w)
    {
        if (this != &w)
        {
            release();
            cnt = w.cnt;
            cnt->w++;
            _ptr = w._ptr;
        }
        return *this;
    }
    WeakPtr<T> &operator=(SharePtr<T> &s)
    {
        cout << "w = s" << endl;
        release();
        cnt = s.cnt;
        cnt->w++;
        _ptr = s._ptr;
        return *this;
    }
    SharePtr<T> lock()
    {
        return SharePtr<T>(*this);
    }
    bool expired()
    {
        if (cnt)
        {
            if (cnt->s > 0)
            {
                cout << "empty " << cnt->s << endl;
                return false;
            }
        }
        return true;
    }
    friend class SharePtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值
    
protected:
    void release()
    {
        if (cnt)
        {
            cnt->w--;
            cout << "weakptr release" << cnt->w << endl;
            if (cnt->w < 1 && cnt->s < 1)
            {
                //delete cnt;
                cnt = NULL;
            }
        }
    }

private:
        T *_ptr;
    Counter *cnt;
};

weak_ptr обычно конфигурируется share_ptr, просрочен, проверяя исходный указатель функции пуст, замок превращается в share_ptr.

рекомендация

отwww.cnblogs.com/WindSun/p/11444429.html