{{ :lang:cpp:smartptr:cpp_smart_pointers_ebook.pdf |C++ smart pointers fluentcpp}}
====Durée de vie====
Lors d'un ''reset'', le nouvel objet commence par être construit avant de détruire le précédent. Si les objets ont une place importante en mémoire, il peut être intéressant de commencer par faire un ''reset()'' avant de faire le ''reset(...)''.
#include
#include
class A {
public:
A() { std::cout << "Constructor\n"; }
~A() { std::cout << "Destructor\n"; }
};
int main() {
std::shared_ptr a = std::make_shared();
a.reset(new A());
a = std::make_shared();
}
Sortie :
Constructor
Constructor
Destructor
Constructor
Destructor
Destructor
====Préserver l'attribut const sur les pointeurs====
Il faut utiliser ''std::propagate_const>%%''.
Il existe aussi ''indirect_value'' qui peut se substituer à ''std::propagate_const>%%''. Attention, ''indirect_value'' ne permet pas de se substituer à ''std::propagate_const>%%'' (voir [[https://github.com/jbcoe/indirect_value/issues/106|Can I replace shared_ptr by indirect_value ?]] {{ :lang:cpp:smartptr:can_i_replace_shared_ptr_by_indirect_value_issue_106_jbcoe_indirect_value_github_18_10_2022_13_27_26_.html |Archive du 04/08/2022 le 18/10/2022}}).
Soit la classe commune ''X'' :
struct X
{
void g() const { std::cout << "g (const)\n"; }
void g() { std::cout << "g (non-const)\n"; }
};
et le programme commun :
int main()
{
Y y;
y.f();
const Y cy;
cy.f();
}
* Cas avec la classe ''X'' intégrée dans une classe ''Y'' avec pointeur classique
struct Y
{
Y() { }
void f() const
{
std::cout << "f (const)\n";
m_ptrX.g();
}
void f()
{
std::cout << "f (non-const)\n";
m_ptrX.g();
}
// Ici, X est une instance sans pointeur.
X m_ptrX;
};
Rendu sans surprise :
f (non-const)
g (non-const)
f (const)
g (const)
Si la méthode ''f const'' est appelée, la méthode ''g const'' est appelée également car une méthode ''const'' ne peut pas appeler une méthode non ''const''.
* Cas avec un pointeur intelligent
struct Y
{
Y() : m_ptrX{} { }
void f() const
{
std::cout << "f (const)\n";
m_ptrX->g();
}
void f()
{
std::cout << "f (non-const)\n";
m_ptrX->g();
}
std::unique_ptr m_ptrX;
};
Rendu :
f (non-const)
g (non-const)
f (const)
g (non-const)
On ne respecte l'obligation d'appeler des méthodes ''const'' depuis une méthode ''const''.
* Cas avec un pointeur unique et propagate_const
Prérequis : minimum clang 3.9, gcc 6.1. Pas dans Visual Studio 2017 [[https://github.com/jbcoe/propagate_const|sauf sur GitHub]].
#include
std::experimental::propagate_const> m_ptrX;
Rendu :
f (non-const)
g (non-const)
f (const)
g (const)
====Encapsuler fopen/close====
std::unique_ptr fp(std::fopen(filename.c_str(), "r"), &fclose);
[[https://stackoverflow.com/questions/26360916/using-custom-deleter-with-unique-ptr|using custom deleter with unique_ptr]] {{ :lang:cpp:smartptr:c_-_using_custom_deleter_with_unique_ptr_-_stack_overflow_28_12_2022_10_34_58_.html |Archive du 14/10/2014 le 28/12/2022}}
====weak_ptr====
====std::weak_ptr en tant que clé dans un conteneur====
Il faut utiliser le comparateur ''owner_less''.
std::map> destination;
===Différencier empty et expired===
Sans passer par ''.lock()'' pour ''empty()''.
#include
#include
class A {};
int main() {
{
std::weak_ptr aa;
if (!aa.owner_before(std::weak_ptr{}) && !std::weak_ptr{}.owner_before(aa)) {
std::cout << "empty1\n";
}
if (aa.expired()) {
std::cout << "expired1\n";
}
}
{
std::shared_ptr a;
std::weak_ptr aa = a;
if (!aa.owner_before(std::weak_ptr{}) && !std::weak_ptr{}.owner_before(aa)) {
std::cout << "empty2\n";
}
if (aa.expired()) {
std::cout << "expired2\n"; // False
}
}
{
std::weak_ptr aa;
{
std::shared_ptr a = std::make_shared();
aa = a;
if (!aa.owner_before(std::weak_ptr{}) && !std::weak_ptr{}.owner_before(aa)) {
std::cout << "empty3\n"; // False
}
if (aa.expired()) {
std::cout << "expired3\n"; // False
}
}
if (!aa.owner_before(std::weak_ptr{}) && !std::weak_ptr{}.owner_before(aa)) {
std::cout << "empty4\n"; // False
}
if (aa.expired()) {
std::cout << "expired4\n";
}
}
return 0;
}