Guide de développement Boost - 3.6weak_ptr

faible_ptr

faible_ptr est une sorte de pointeur intelligent introduit pour coopérer avec shared_ptr. Il ressemble plus à un assistant de shared_ptr qu'à un pointeur intelligent, car il n'a pas le comportement des pointeurs ordinaires et ne surcharge pas les opérateurs * et ->. Son rôle le plus important est d'aider shared_ptr à observer l'utilisation des ressources comme un spectateur.

résumé de la classe

template<class T>
class weak_ptr
{
    
    
public:
   weak_ptr(); //构造函数
   template<class Y> weak_ptr(shared_ptr<Y> const & r);
   weak_ptr(weak_ptr const & r);
   ~weak_ptr(); //析构函数
   weak_ptr &operator = (weak_ptr const & r); //赋值
   long use_count() const; //引用计数
   bool expired() const; //是否失效指针
   shared_ptr<T> lock() const; //获取shared_ptr
   void reset(); //重置指针
   void swap(weak_ptr<T> & b); //交换指针
};

L'interface de faiblesse_ptr est très petite, tout comme son nom, c'est un pointeur "faible", mais il peut faire un travail spécial, ce qui est suffisant pour prouver sa valeur d'existence.

usage

low_ptr est conçu pour fonctionner avec shared_ptr et peut être construit à partir d'un shared_ptr ou d'un autre objet low_ptr pour obtenir le droit d'observer les ressources. Mais faiblesse_ptr ne partage pas les ressources et sa construction n'augmentera pas le nombre de références du pointeur. De même, lorsque faible_ptr est détruit, cela ne fera pas diminuer le nombre de références, c'est juste un observateur silencieux.

Utilisez la fonction membre use_count() de low_ptr pour observer le nombre de références de la ressource. La fonction d'une autre fonction membre expired() est équivalente à use_count()==0, mais plus rapide, indiquant la ressource observée (c'est-à-dire gérée par ressources shared_ptr) n'existent plus.

faiblesse_ptr n'est pas surchargé operator*, ->ce qui est intentionnel, car il ne partage pas de pointeurs et ne peut pas exploiter les ressources, c'est pourquoi il est "faible". Mais il peut utiliser une fonction membre très importante lock() pour obtenir un objet shared_ptr disponible à partir du shared_ptr observé, convertir la relation faible en une relation forte et ainsi exploiter les ressources. Mais quand expired()==true, la fonction lock() retournera un shared_ptr qui stocke un pointeur nul.

shared_ptr<int> sp(new int(10)); //一个shared_ptr
assert(sp.use_count() == 1);

weak_ptr<int> wp(sp); //从shared_ptr创建weak_ptr
assert(wp.use_count() == 1); //weak_ptr不影响引用计数

if (!wp.expired()) //判断weak_ptr观察的对象是否失效
{
    
    
	shared_ptr<int> sp2 = wp.lock(); //获得一个shared_ptr
	*sp2 = 100;
	assert(wp.use_count() == 2); //退出作用域,sp2自动析构,引用计数减1
}

assert(wp.use_count() == 1);
sp.reset(); //shared_ptr失效
assert(wp.expired());
assert(!wp.lock()); //weak_ptr将获得一个空指针

enable_shared_from_this

Une utilisation importante de faiblesse_ptr est d'obtenir le pointeur_partagé de ce pointeur, afin que l'objet puisse produire un pointeur_partagé pour se gérer lui-même : l'objet utilise pointeur_faible pour observer le pointeur this, qui n'affecte pas le nombre de références, et appelle la fonction lock() si nécessaire, et en renvoie un qui répond aux exigences Le shared_ptr est destiné à un usage extérieur.

Cette solution est implémentée sous forme d'idiome en <boost/enable_shared_from_this.hpp>définissant une classe d'assistance dans le fichier d'en-tête enable_shared_from_this<T>dont la déclaration est résumée comme suit :

template<class T>
class enable_shared_from_this  //辅助类,需要继承使用
public:
   shared_ptr<T> shared_from_this(); //工厂函数,产生this的shared_ptr

Lorsque vous l'utilisez, vous n'avez qu'à en dériver la classe que vous souhaitez gérer par shared_ptr, et la fonction membre shared_from_this() renverra le shared_ptr de this. Par exemple:

class self_shared: //一个需要用shared_ptr自我管理的类
   public enable_shared_from_this<self_shared>
{
    
    
public:
   self_shared(int n) : x(n){
    
    }
   int x;
   void print()
   {
    
     cout<< "self_shared : " << x << endl; }
};

int main()
{
    
    
     auto sp = make_shared<self_shared>(313);
     sp->print();
     auto p = sp->shared_from_this();
     p->x = 1000;
     p->print();
}

A noter qu'il ne faut pas utiliser shared_from_this() pour obtenir shared_ptr pour un objet ordinaire (objet non géré par shared_ptr), par exemple :

self_shared ss;
auto p = ss.shared_from_this(); //错误

Bien que cela soit grammaticalement correct et qu'il n'y ait aucun problème avec la compilation, cela entraînera une tentative de suppression d'un objet alloué sur la pile lorsque le ptr partagé est détruit lors de l'exécution, et un comportement indéfini se produit.

enable_shared_from_raw

<boost/smart_ptr/enable_shared_from_raw .hpp>La bibliothèque smart_ptr fournit une autre classe auxiliaire enable_shared_from_raw similaire à enable_shared_from_this dans le fichier d'en-tête non documenté . Elle ne nécessite pas que l'objet soit géré par un shared_ptr et peut créer directement un shared_ptr à partir d'un pointeur brut.

Le résumé de classe de enable_shared_from_raw est le suivant :

class enable_shared_from_raw
{
    
    
protected:
   enable_shared_from_raw();
   enable_shared_from_raw(enable_shared_from_raw const &);
   enable_shared_from_raw & operator=(enable_shared_from_raw const &);
   ~enable_shared_from_raw()
private :
   template<class Y> friend class shared_ptr;
   template<typenameT>
   friend boost::shared_ptr<T> shared_from_raw(T *);
   template<typename T>
   friend boost::weak_ptr<T> weak_from_raw(T *);
};

enable_shared_from_raw tire parti de la fonctionnalité de constructeur d'alias de shared_ptr et contient un void*pointeur nul shared_ptr en interne en tant qu'observateur du comptage de références, afin d'atteindre l'objectif de gestion des pointeurs bruts.

enable_shared_from_raw doit également être hérité, mais ce n'est pas une classe de modèle, il n'est donc pas nécessaire de spécifier des paramètres de modèle, ce qui est plus simple que enable_shared_from_this. Il ne fournit pas de fonction membre shared_from_this(), mais utilise deux fonctions amies shared_from_raw() et faiblesse_from_raw() pour terminer le travail de création de pointeurs intelligents.

Mais s'il vous plaît noter: Après avoir appelé shared_from_raw(), en raison de l'existence de variables membres shared_ptr, il y aura une référence forte à shared_ptr à l'intérieur de l'objet, donc même si d'autres shared_ptr sont détruits, le pointeur brut ne sera pas automatiquement supprimé (parce que use_count ( ) >= 1) - Cela rend enable_shared_from_raw légèrement différent de enable_shared_from_this en ce sens qu'il peut créer en toute sécurité un shared_ptr à partir d'un objet simple au lieu d'un pointeur.

Le code démontrant l'utilisation de enable_shared_from_raw est le suivant :

#include <boost/smart_ptr/enable_shared_from_raw.hpp>

class raw_shared :
	public boost::enable_shared_from_raw
{
    
    
public:
	raw_shared()
	{
    
    
		std::cout << "raw_shared ctor" << std::endl;
	}
	~raw_shared()
	{
    
    
		std::cout << "raw_shared dtor" << std::endl;
	}
};

int main()
{
    
    
	raw_shared x; //一个普通对象
	assert(weak_from_raw(&x).use_count() == 1); //此时无引用,注意要用&取地址
	
	auto px = shared_from_raw(&x); //获取shared_ptr
	assert(px.use_count() == 2); //引用计数为2!
} //对象自动删除

Soyez prudent lorsque vous appliquez enable_shared_from_raw aux pointeurs bruts, une mauvaise utilisation peut entraîner des fuites de mémoire :

int main()
{
    
    
	auto p = new raw_shared; //创建一个原始指针

	auto wp = weak_from_raw(p); //获取weak_ptr
	assert(wp.use_count() == ); //此时无引用

	auto sp = shared_from_raw(p); //获取shared_ptr
	assert(sp.use_count() == 2); //引用计数为2!

	auto sp2 = sp; //拷贝一个shared_ptr
	auto wp2 = weak_from_raw(p); //获取weak_ptr
	assert(wp2.use_count() == 3); //引用计数为3
} //对象没有被删除,内存泄露!

Si, à un moment donné dans le code, un shared_ptr est utilisé pour gérer le pointeur brut - au lieu d'appeler shared_from_raw(), la gestion du pointeur est transférée au shared_ptr afin qu'il puisse être correctement autodétruit, par exemple :

int main()
{
    
    
	auto p = new raw_shared; //创建一个原始指针
    decltype(shared_from_raw(p)) spx(p); //使用shared_ptr管理指针
	... //其他操作
} //对象被自动删除

L'utilisation de enable_shared_from_raw est assez spéciale et il existe peu de scénarios d'application réels, c'est peut-être pour cela qu'il n'est pas documenté dans la bibliothèque Boost.

rompre les références circulaires

Parfois, il peut y avoir des "références circulaires" dans le code, et le mécanisme de comptage de références de shared_ptr échouera, entraînant l'échec de la libération correcte des ressources, par exemple :

#include <boost/smart_ptr.hpp>
using namespace boost;

class node //一个用于链表节点的类
{
    
    
public:
	~node() //析构函数输出信息
	{
    
    
		std::cout << "deleted" << std::endl;
	}

	typedef shared_ptr<node> ptr_type; //指针类型使用shared_ptr
	ptr_type next; //后继指针
};

int main()
{
    
    
	auto p1 = make_shared<node>(); //两个节点对象
	auto p2 = make_shared<node>();

	p1->next = p2; //形成循环链表
	p2->next = p1; 

	assert(p1.use_count() == 2); //每个shared_ptr的引用计数都是2
	assert(p2.use_count() == 2);

} //退出作用域,shared_ptr无法正确析构

Dans le code ci-dessus, les deux objets nœuds contiennent des références l'un à l'autre, et le nombre de références de chaque shared_ptr est 2, de sorte que le nombre de références n'est pas réduit à 0 lors de la destruction, et l'opération de suppression ne sera pas appelée, ce qui entraînera une mémoire fuir.

À ce stade, nous pouvons utiliser faiblesse_ptr, car cela n'augmentera pas le nombre de références du pointeur intelligent, changeant ainsi la référence forte d'origine en une référence faible, brisant le cycle où il peut y avoir une référence circulaire et appelant shared_ptr quand il a vraiment besoin shared_ptr La fonction lock() de low_ptr :

class node //一个用于链表节点的类
{
    
    
public:
	~node() //析构函数输出信息
	{
    
    
		std::cout << "deleted" << std::endl;
	}

	typedef weak_ptr<node> ptr_type; //指针类型使用weak_ptr
	ptr_type next; //后继指针
};

int main()
{
    
    
	auto p1 = make_shared<node>(); //两个节点对象
	auto p2 = make_shared<node>();

	p1->next = p2; //形成循环链表
	p2->next = p1; //引用使用了weak_ptr所以正常

	assert(p1.use_count() == 1); //每个shared_ptr的引用计数都是2
	assert(p2.use_count() == 1); //没有了循环引用

    if (!p1->next.expired()) //检查弱引用是否有效
	{
    
    
		auto p3 = p1->next.lock(); //调用lock()获得强引用
	}

} //退出作用域,shared_ptr均正确析构

exemple de code

#include <iostream>
//using namespace std;

#include <boost/smart_ptr.hpp>
using namespace boost;

//

void case1()
{
    
    
	shared_ptr<int> sp(new int(10));
	assert(sp.use_count() == 1);

	weak_ptr<int> wp(sp);
	assert(wp.use_count() == 1);
	assert(!wp.empty());

	if (!wp.expired())
	{
    
    
		shared_ptr<int> sp2 = wp.lock();
		*sp2 = 100;
		assert(wp.use_count() == 2);
	}

	assert(wp.use_count() == 1);
	sp.reset();
	assert(wp.expired());
	assert(!wp.lock());
}

//

class self_shared :
	public enable_shared_from_this<self_shared>
{
    
    
public:
	self_shared(int n) :x(n) {
    
    }
	int x;
	void print()
	{
    
    
		std::cout << "self_shared:" << x << std::endl;
	}
};

void case2()
{
    
    
	auto sp = make_shared<self_shared>(313);
	sp->print();

	auto p = sp->shared_from_this();

	p->x = 1000;
	p->print();
}

//

class node
{
    
    
public:
	~node()
	{
    
    
		std::cout << "deleted" << std::endl;
	}

	typedef weak_ptr<node> ptr_type;
	//typedef shared_ptr<node> ptr_type;
	ptr_type next;
};

void case3()
{
    
    
	auto p1 = make_shared<node>();
	auto p2 = make_shared<node>();

	p1->next = p2;
	p2->next = p1;

	assert(p1.use_count() == 1);
	assert(p2.use_count() == 1);

	if (!p1->next.expired())
	{
    
    
		auto p3 = p1->next.lock();
	}
}

//
#include <boost/smart_ptr/enable_shared_from_raw.hpp>

class raw_shared :
	public enable_shared_from_raw
{
    
    
public:
	raw_shared()
	{
    
    
		std::cout << "raw_shared ctor" << std::endl;
	}
	~raw_shared()
	{
    
    
		std::cout << "raw_shared dtor" << std::endl;
	}
};

void case4()
{
    
    
	raw_shared x;
	assert(weak_from_raw(&x).use_count() == 1);
	auto px = shared_from_raw(&x);
	assert(px.use_count() == 2);

	auto p = new raw_shared;

	auto wp = weak_from_raw(p);
	assert(wp.use_count() == 1);

	decltype(shared_from_raw(p)) spx(p);

	auto sp = shared_from_raw(p);
	//std::cout << sp.use_count() << std::endl;
	assert(sp.use_count() == 2);

	//decltype(sp) spx(p);

	auto sp2 = sp;
	auto wp2 = weak_from_raw(p);
	assert(wp2.use_count() == 3);
}

//

int main()
{
    
    
	case1();
	case2();
	case3();
	case4();
}

insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/qq_36314864/article/details/132021200
conseillé
Classement