0

If I have two pointers of the same type and one is null, is there a function/obvious one-liner that can efficiently return the one that's not null? I know that I can do this with some nested if blocks, but I'm just wondering if there's a more compact way to do it.

Edit: It would be optimal if this could also return null if both or neither are defined.

phuclv
  • 37,963
  • 15
  • 156
  • 475
DaBooba
  • 53
  • 10
  • 4
    `return a?a:b;` ? – tkausl Apr 14 '19 at 03:10
  • 2
    Compactness isn't particularly helpful. `if (a == nullptr) return b; else return a;` is likely to generate the same code as `return a ? a : b;`. Optimize for readability. (Personally, I find the conditional operator readable enough. YMMV.) You should also think about what to do if both pointers are null, or if neither is. If you don't want to handle that case, that's ok, but you should document it as a requirement on the caller. – Keith Thompson Apr 14 '19 at 03:18
  • @tkausl Sorry I was in the middle of an edit when you posted that. – DaBooba Apr 14 '19 at 03:23
  • @KeithThompson Ternary would've been fine but I do want to handle the case where both/neither are defined. – DaBooba Apr 14 '19 at 03:25
  • Can one not chain ternary statements in cpp? – Adrian M. Apr 14 '19 at 03:37

4 Answers4

2

Conditional operator:

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

To return null if both are not null:

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

If both are null, returning either one will return null.

Cosmin
  • 21,216
  • 5
  • 45
  • 60
  • Ternary is fine, but may need an addition to address *"... return null if both ... are defined."* (which may have been added after your answer) – David C. Rankin Apr 14 '19 at 03:17
  • @DavidC.Rankin It was, I'm sorry. Although I had completely forgotten about ternary conditionals, it doesn't look like (at least obviously) that I can use them for evaluating all 4 cases. – DaBooba Apr 14 '19 at 03:22
  • Good update, I like it, but I always have to take a double-look to sort out double-ternarys `:)` Fix is worth the UV. – David C. Rankin Apr 14 '19 at 03:25
  • Explicit comparison to `nullptr` is unnecessary as `std::nullptr_t` is implicitly convertible to `bool`: see [\[conv.bool\]](https://timsong-cpp.github.io/cppwp/n4659/conv.bool) via [\[conv\]/4](https://timsong-cpp.github.io/cppwp/n4659/conv#4). – pandorafalters Apr 14 '19 at 06:47
0

Edit: It would be optimal if this could also return null if both or neither are defined.

If you want to return only the unique non-nullptr between pointers a and b, you could do something similar to:

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 */
}
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

In other languages this feature is called coalesce. Like in sql. Apparently there is no built-in function but here is a discussion of different approaches to implement it C# null coalescing operator equivalent for c++

Dr Phil
  • 833
  • 6
  • 18
0

Here's a branchless bitwise version

void* getUniquePointer(const void * const a, const void * const b)
{
   // mask = ALL ONES if only one of a and b is null, 0 otherwise
   auto mask = -(uintptr_t)(!!a ^ !!b);
   return (void*)(((uintptr_t)a | (uintptr_t)b) & mask);
}

Clang will compile it to

    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

Godbolt link for comparison with other solutions

If you don't need to return null if both are defined then it'll be even simpler

void* getUniquePointer(const void *a, const void *b)
{
   return (void*)((uintptr_t)a | (uintptr_t)b);
}
phuclv
  • 37,963
  • 15
  • 156
  • 475