web-dev-qa-db-fra.com

Comment vérifier si faible_ptr est vide (non assigné)?

Existe-t-il un moyen de faire la distinction entre un faible_ptr attribué (éventuellement expiré) et un non-affecté.

weak_ptr<int> w1;
weak_ptr<int> w2 = ...;

Je comprends les vérifications suivantes relatives à la non-affectation ou à l'expiration, mais existe-t-il une vérification (moins chère?) Uniquement pour la non-affectation?

if (!w.lock()) { /* either not assigned or expired */ }
13
Zuza

Vous pouvez utiliser deux appels à owner_before pour vérifier l’égalité avec un pointeur faible construit (vide) par défaut:

template <typename T>
bool is_uninitialized(std::weak_ptr<T> const& weak) {
    using wt = std::weak_ptr<T>;
    return !weak.owner_before(wt{}) && !wt{}.owner_before(weak);
}

Ceci ne renverra que true si w{} "==" weak, où "==" compare le propriétaire, et selon en.cppreference.com :

L'ordre est tel que deux pointeurs intelligents ne se comparent comme équivalents que s'ils sont tous les deux vides ou s'ils possèdent le même objet, même si les valeurs des pointeurs obtenus par get () sont différentes (par exemple parce qu'ils pointent sur des sous-objets différents dans le même objet). objet).

Étant donné que le constructeur par défaut construit un pointeur {vide _ faible, il ne peut renvoyer true que si weak est également videNot retournera true si weak a expiré.

En regardant l'Assemblée générée (avec optimisation), cela semble plutôt optimisé:

bool is_uninitialized<int>(std::weak_ptr<int> const&):
        cmp     QWORD PTR [rdi+8], 0
        sete    al
        ret

... comparé à la vérification de weak.expired():

bool check_expired(std::weak_ptr<int> const&):
        mov     rdx, QWORD PTR [rdi+8]
        mov     eax, 1
        test    rdx, rdx
        je      .L41
        mov     eax, DWORD PTR [rdx+8]
        test    eax, eax
        sete    al
.L41:
        rep ret

... ou renvoie !weak.lock() (~ 80 lignes d'assemblage).

17
Holt

Utiliser std :: faible_ptr :: expired ()

#include <iostream>
#include <memory>

//declare a weak pointer
std::weak_ptr<int> gw;

void f()
{
    //check if expired
    if (!gw.expired()) {
        std::cout << "pointer is valid\n";
    }
    else {
        std::cout << "pointer  is expired\n";
    }
}

int main()
{
    f();
    {
        auto cre = std::make_shared<int>(89);
        gw = cre;
        f();
    } 

    f();
}

Sortie

pointer  is expired
pointer is valid
pointer  is expired
Program ended with exit code: 0
1
Hariom Singh

Vous pouvez essayer de créer un pointeur partagé qui accepte un pointeur faible en tant que paramètre et lève une exception std :: bad_weak_ptr si un pointeur faible est arrivé à expiration (ou n’est pas affecté comme dans votre cas):

#include <memory>
#include <iostream>
int main(){
    // with an assigned pointer
    std::shared_ptr<int> p1(new int(42));
    std::weak_ptr<int> w1(p1);
    try {
        std::shared_ptr<int> p2(w1);
    }
    catch (const std::bad_weak_ptr& e) {
        std::cout << e.what() << '\n';
    }
    // with a non assigned pointer
    std::shared_ptr<int> p2(new int(42));
    std::weak_ptr<int> w2;
    try {
        std::shared_ptr<int> p2(w2); // raises an exception
    }
    catch (const std::bad_weak_ptr& e) {
        std::cout << "Ptr 2: " << e.what() << '\n';
    }
}
0
Ron