"faible ptr::expiré le comportement dans le dtor de l'objet

Considérons le code suivant:

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

class T;

std::weak_ptr<T> wptr;

class T
{
public:
    T() {  }
    ~T() {
        std::cout << "in dtor" << std::endl;
        std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
    }
};

int main() {
    {
        auto ptr = std::make_shared<T>();
        wptr = ptr;
        std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
    }
    return 0;
}

Dans ce code, j'ai essayé de savoir si weak_ptr s sont expirés dans la phase de destruction des objets. Il semble donc. La sortie est:

not expired
in dtor
expired

j'ai utilisé gcc-5.1 ideone.

Maintenant, j'ai un autre problème. Je n'ai trouvé aucune documentation indiquant que c'est le comportement standard. Est-il garanti pour fonctionner de cette façon, toujours?

15
demandé sur Cheers and hth. - Alf 2017-01-25 15:20:41
la source

4 ответов

Maintenant, j'ai un autre problème. Je n'ai trouvé aucune documentation indiquant que c'est le comportement standard. Est-il garanti pour fonctionner de cette façon, toujours?

Non. En effet, il est sous-spécifié dans la norme, comme soulevé par LWG question 2751.

la norme C++14 ne contient aucun langage qui garantisse le fonctionnement du deleter par un shared_ptr va voir tous les associés weak_ptr des instances comme ayant expiré. Pour par exemple, la norme ne semble pas garantir que l'affirmation dans le snippet suivant Ne va pas tirer:

std::weak_ptr<Foo> weak;
std::shared_ptr<Foo> strong{
  new Foo,
  [&weak] (Foo* f) {
    assert(weak.expired());
    delete f;
  },
};

weak = strong;
strong.reset();

Il semble clair que l'intention est associé weak_ptrs sont expirés, parce que sinon shared_ptr les deleters pourraient ressusciter une référence à un objet qui est supprimé.

solution suggérée: 23.11.3.2 [util.smartptr.partager.dest] devrait spécifier que la diminution de l' use_count() causé par le destructeur est séquencé avant l'appel à la deleter ou l'appel à delete p.

la formulation actuelle de ~shared_ptr() comme indiqué ci-dessus, le deleter est simplement invoqué, avec une note non-normative que le nombre de cas où la propriété de l'action est réduite.

alors que l'intention est probablement que weak.expired() quand le deleter est appelé, il est discutable de se fier à cela. Il est vraiment raisonnable d'affirmer avec confiance que le shared_ptr n'est plus actionnaire après il a été détruit-poser cette question cours la destruction est un peu étrange.

7
répondu Barry 2018-01-26 22:33:37
la source

utiliser make_shared comme ça va créer un objet avec le constructeur par défaut que vous avez fourni.

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );

Construit un objet de type T et l'enveloppe dans un std::shared_ptr en utilisant args comme liste de paramètres pour le constructeur de T. l'objet est construit comme si par l'expression (std:: make_shared)

après la portée anonyme dans l'ensemble. Le ptr partagé sera supprimé.

L'objet est détruit et sa mémoire désallouée, lorsque l'une des la suite se passe:

le dernier shared_ptr posséder l'objet est détruit; (std:: shared_ptr)

.

Le destructeur de shared_ptr décrémente le nombre de communes propriétaires de le bloc de contrôle. Si le compteur atteint zéro, le bloc de contrôle appelle le destructeur de l'objet géré. Le bloc de contrôle ne se désallouer jusqu'à ce que le std::weak compteur atteint zéro bien. std::shared_ptr notes de mise en Œuvre

cela signifie que votre objet appellera son destructeur après que la destruction du dernier ptr partagé a commencé. La sortie:

not expired
in dtor
expired

est le comportement attendu.

5
répondu Petar Velev 2018-01-26 14:30:59
la source

Pas de la norme elle-même, mais:

http://en.cppreference.com/w/cpp/memory/weak_ptr/expired

Vérifie si l'objet géré a déjà été supprimé. Équivalent pour use_count() == 0.

alors c'est une question de temps use_count est défini à 0 avant ou après suppression. Maintenant, il y a un non sur ceci dans un projet de la norme: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf [page 566 20.9.2.2.2]

~shared_ptr();

Effets:

  • Si *this est vide ou partage la propriété avec un autre shared_ptr exemple (use_count() > 1), il n'y a pas d'effets secondaires.
  • Sinon, si *this possède un objet p et un deleter d,d(p) est appelée.
  • Sinon, *this possède un pointeur p et delete p est appelée.

[Note: depuis la destruction de *this diminue le nombre de instances qui partagent la propriété avec *this par un, après *this a été détruit tous shared_ptr instances qui partageaient la propriété avec *this rapport use_count()c'est un de moins que son précédent valeur. - fin de la remarque]

0
répondu Lanting 2017-01-25 15:55:03
la source

weak_ptr expire lorsqu'il n'y a plus shared_ptrs se référant à l'objet.

Quand (immédiatement après) le dernier shared_ptr cesse de faire référence à l'objet qu'il a détruit.

À ce stade, il n'y a pas shared_ptr S se référant à elle, donc tout weak_ptr a expiré.

le destructeur de l'objet est maintenant invoqué et s'il a un stockage séparé (i.e. n'a pas été créé avec make_shared) son stockage est désallocé.

le bloc de commande, où le le compte de référence et le pointeur brut et la fonction de suppression sont stockés, persiste s'il y a un weak_ptr se réfère à elle. Lors de la dernière weak_ptr cesse de s'y référer, le bloc de contrôle est également détruit et désalloué. I. e., shared_ptr les instances gardent l'objet lui-même vivant, avec son bloc de contrôle, alors que weak_ptr les instances maintiennent le bloc de contrôle en vie.

0
répondu Cheers and hth. - Alf 2018-01-25 15:39:22
la source

Autres questions sur c++ c++11 shared-ptr c++14 weak-ptr