Outils pour utilisateurs

Outils du site


lang:cpp:smartptr

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 <iostream>
#include <memory>
 
class A {
 public:
  A() { std::cout << "Constructor\n"; }
  ~A() { std::cout << "Destructor\n"; }
};
 
int main() {
  std::shared_ptr<A> a = std::make_shared<A>();
  a.reset(new A());
  a = std::make_shared<A>();
}

Sortie :

Constructor
Constructor
Destructor
Constructor
Destructor
Destructor

Préserver l'attribut const sur les pointeurs

Il faut utiliser std::propagate_const<std::unique_ptr<X>>.

Il existe aussi indirect_value qui peut se substituer à std::propagate_const<std::unique_ptr<X>>. Attention, indirect_value ne permet pas de se substituer à std::propagate_const<std::shared_ptr<X>> (voir Can I replace shared_ptr by indirect_value ? 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<X> 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 sauf sur GitHub.

#include <experimental/propagate_const>
  std::experimental::propagate_const<std::unique_ptr<X>> m_ptrX;

Rendu :

f (non-const)
g (non-const)
f (const)
g (const)

Encapsuler fopen/close

std::unique_ptr<FILE, decltype(&fclose)> fp(std::fopen(filename.c_str(), "r"), &fclose);

using custom deleter with unique_ptr 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<U, T, std::owner_less<U>> destination;

Différencier empty et expired

Sans passer par .lock() pour empty().

#include <iostream>
#include <memory>
 
class A {};
 
int main() {
  {
    std::weak_ptr<A> aa;
 
    if (!aa.owner_before(std::weak_ptr<A>{}) && !std::weak_ptr<A>{}.owner_before(aa)) {
      std::cout << "empty1\n";
    }
    if (aa.expired()) {
      std::cout << "expired1\n";
    }
  }
 
  {
    std::shared_ptr<A> a;
    std::weak_ptr<A> aa = a;
 
    if (!aa.owner_before(std::weak_ptr<A>{}) && !std::weak_ptr<A>{}.owner_before(aa)) {
      std::cout << "empty2\n";
    }
    if (aa.expired()) {
      std::cout << "expired2\n";  // False
    }
  }
 
  {
    std::weak_ptr<A> aa;
    {
      std::shared_ptr<A> a = std::make_shared<A>();
      aa = a;
 
      if (!aa.owner_before(std::weak_ptr<A>{}) && !std::weak_ptr<A>{}.owner_before(aa)) {
        std::cout << "empty3\n";  // False
      }
      if (aa.expired()) {
        std::cout << "expired3\n";  // False
      }
    }
    if (!aa.owner_before(std::weak_ptr<A>{}) && !std::weak_ptr<A>{}.owner_before(aa)) {
      std::cout << "empty4\n";  // False
    }
    if (aa.expired()) {
      std::cout << "expired4\n";
    }
  }
  return 0;
}
lang/cpp/smartptr.txt · Dernière modification : 2024/01/11 17:00 de root