Comparing unique_ptrs

I have 2 unique_ptr and need to compare whether they contain the same value or are empty

This is the code:

1
2
3
4
5
6
7
8
9
10
11
struct User {
     int id = 0;
     std::string name;
     std::unique_ptr<int> reports_to;
     bool operator==(const User & o) const {
           bool eq = id == o.id && name == o.name;
           auto val1 = reports_to ? *reports_to : -1;
           auto val2 = o.reports_to ? *o.reports_to : -1;
           return eq && (val1 == val2);
      }
}     


The equality operator is ugly!!

How can i express this more concisely?

Regards,

Juan
Last edited on
If you have two std::unique_ptr pointing to the same object (address), then you did something wrong!

unique_ptr objects own their pointer uniquely: no other facility shall take care of deleting the object, and thus no other managed pointer should point to its managed object, since as soon as they have to, unique_ptr objects delete their managed object without taking into account whether other pointers still point to the same object or not, and thus leaving any other pointers that point there as pointing to an invalid location.


Anyhow, I think you can do:
1
2
3
4
static bool equals(std::unique_ptr<int> &ptr1, std::unique_ptr<int> &ptr2)
{
    return ptr1.get() == ptr2.get();
}

Or, even better:
1
2
3
4
5
6
7
8
static bool equals(std::unique_ptr<int> &ptr1, std::unique_ptr<int> &ptr2)
{
    if (ptr1.get() == ptr2.get())
    {
        throw std::runtime_error("This is not supposed to happen!");
    }
    return false;
}
Last edited on
unique_ptr implements the == operator. How does it work, what does it compare ?
unique_ptr implements the == operator. How does it work, what does it compare ?


It just returns false! (kidding).

according to the web (not kidding anymore) it returns
x.get() == y.get()

the only time I can see that being true would be empty / null ?
Last edited on
It would return true if you compared the unique_ptr object with itself.
Last edited on
Also, technically, you could wrap the same "raw" pointer into two distinct unique_ptr objects.

This must not be done, because the first of the two unique_ptr instances that goes out of scope will destroy the object, leaving the other unique_ptr instance with a dangling pointer! Still, you could do that...
Last edited on
This must not be done


It could make sense if there was a custom deleter involved. Maybe there's a device that can be initialized multiple times, but must be uninitialized the same number of times. unique_ptr provides one way to do this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <cstdio>
#include <memory>
#include <cassert>

struct device 
{
  int times_initialized = 0;
  ~device() { assert(times_initialized == 0); }
};

void initialize(device& d) noexcept { ++d.times_initialized; }
void uninitialize(device& d) noexcept { --d.times_initialized; }

struct device_deleter
{
  void operator()(device* d) const noexcept { uninitialize(*d); } 
};

int main()
{
  device d; 
  
  initialize(d);
  std::unique_ptr<device, device_deleter> pd1 {&d};
  
  initialize(d);
  std::unique_ptr<device, device_deleter> pd2 {&d};
  
  assert(pd1 == pd2); 
}


Last edited on
I think you are effectively emulating the "reference counting" mechanism here, with a unique_ptr and a custom deleter, even though std::shared_ptr already provides exactly that out-of-the-box:
https://www.cplusplus.com/reference/memory/shared_ptr/
Last edited on
I think that's one way to look at it, but device could be a third-party thing. I've found this multiple initialization pattern to be fairly common.

In this setup, each unique_ptr assumes a unique responsibility for uninitializing the device. This
is somewhat different than sharing one responsibility across multiple shared_ptrs. And the costs are lower, since this way the reference counting is only done once, by the device.

Maybe a custom scope_guard type would be more suitable. unique_ptr does the job, but it only works for pointer-like resources.
Last edited on
Topic archived. No new replies allowed.