0
votes

Existe-t-il une fonction qui prend 2 pointeurs et renvoie celle qui n'est pas NULL?

Si j'ai deux pointeurs du même type et que l'un est nul, y a-t-il une fonction / une seule ligne évidente qui peut renvoyer efficacement celle qui n'est pas nulle? Je sais que je peux le faire avec des blocs if imbriqués, mais je me demande simplement s'il existe un moyen plus compact de le faire.

Edit: Ce serait optimal si cela pouvait également renvoyer null si les deux ou aucun des deux ne sont définis.


5 commentaires

Retour A? A: B; ?


La compacité n'est pas particulièrement utile. if (a == nullptr) retourne b; else return a; est susceptible de générer le même code que return a? a: b; . Optimisez la lisibilité. (Personnellement, je trouve que l'opérateur conditionnel est suffisamment lisible. YMMV.) Vous devriez également réfléchir à ce qu'il faut faire si les deux pointeurs sont nuls, ou si ni l'un ni l'autre ne l'est. Si vous ne souhaitez pas gérer ce cas, ce n'est pas grave, mais vous devez le documenter comme une exigence sur l'appelant.


@tkausl Désolé, j'étais au milieu d'une modification lorsque vous avez publié cela.


@KeithThompson Ternary aurait été bien mais je veux gérer le cas où les deux / ni l'un ni l'autre ne sont définis.


Ne peut-on pas enchaîner les déclarations ternaires dans cpp?


4 Réponses :


2
votes

Opérateur conditionnel:

pointer = (p1 && p2) ? nullptr : ((p1 != nullptr) ? p1 : p2);

Pour renvoyer null si les deux ne sont pas nuls:

pointer = (p1 != nullptr) ? p1 : p2;

Si les deux sont nuls, renvoyer l'un ou l'autre sera renvoie null.


4 commentaires

Le ternaire est très bien, mais peut nécessiter un ajout à l'adresse "... return null si les deux ... sont définis." (qui peut avoir été ajouté après votre réponse)


@ DavidC.Rankin C'était, je suis désolé. Bien que j'aie complètement oublié les conditions ternaires, il ne semble pas (du moins évidemment) que je puisse les utiliser pour évaluer les 4 cas.


Bonne mise à jour, j'aime bien, mais je dois toujours y jeter un coup d'œil pour trier les doubles ternaires :) Le correctif vaut la peine.


Une comparaison explicite avec nullptr n'est pas nécessaire car std :: nullptr_t est implicitement convertible en bool : voir [conv.bool] via [conv] / 4 .



0
votes

Edit: Ce serait optimal si cela pouvait également renvoyer null si les deux ou aucun n'est défini.

Si vous souhaitez renvoyer uniquement l'unique non-nullptr entre les pointeurs a et b , vous pouvez faire quelque chose de similaire à:

void *rtn_defined_unique (const void *a, const void *b)
{
    /* if neither or both, return NULL */
    if ((a == nullptr && b == nullptr) || (a && b))
        return NULL;

    if (a != nullptr)   /* if a, return a */
        return a;

    return b;           /* otherwise, it's b */
}

0 commentaires

0
votes

Dans d'autres langues, cette fonctionnalité est appelée coalesce. Comme dans sql. Apparemment, il n'y a pas de fonction intégrée mais voici une discussion des différentes approches pour l'implémenter Opérateur de fusion nul C # équivalent pour c ++


0 commentaires

0
votes

Voici une version bit à bit sans branche

void* getUniquePointer(const void *a, const void *b)
{
   return (void*)((uintptr_t)a | (uintptr_t)b);
}

Clang la compilera en

    test    rdi, rdi
    setne   al
    test    rsi, rsi
    setne   cl
    xor     cl, al
    or      rsi, rdi
    xor     eax, eax
    test    cl, cl
    cmovne  rax, rsi
    ret

lien Godbolt pour la comparaison avec d'autres solutions p>

Si vous ne avez pas besoin de null retour si les deux sont définis alors ce sera encore plus simple

void* getUniquePointer(const void * const a, const void * const b)
{
   auto mask = -(uintptr_t)(!!a ^ !!b); // all ones if only one is defined, 0 otherwise
   return (void*)(((uintptr_t)a | (uintptr_t)b) & mask);
}


0 commentaires