Simple code to use either unique_ptr
or shared_ptr
as a scope guard. All information about what to clear is captured in the deleter
, so I though it is safe to use nullptr
for constructor.
Apparently, with Visual C++ 2017 (14.1), it is not working as expected for unique_ptr
, but works for shared_ptr
. Is it a Microsoft quirk, or does the standard prevent calling the deleter
of a unique_ptr
when holding nullptr
?
In the code below, I'm forced to construct a unique_ptr
with (void*)1
. If I construct it with nullptr
, cleaner
won't be called. For shared_ptr
, there is no difference, cleaner
is always called.
#include <memory>
#include <iostream>
int main()
{
int ttt = 77;
auto cleaner = [&ttt](void*) {
std::cout << "cleaner: " << ttt << "\n"; // do something with capture here instead of print
};
std::unique_ptr<void, decltype(cleaner)> p((void*)1, cleaner);
std::shared_ptr<void> q(nullptr, [&ttt](void*) {
std::cout << "shared: " << ttt << "\n"; // do something with capture here instead of print
});
std::cout << "done\n";
return 0;
}
unique_ptr
's destructor is required to do so:
23.11.1.2.2 unique_ptr destructor [unique.ptr.single.dtor]
2 Effects: If
get() == nullptr
there are no effects. Otherwiseget_deleter()(get())
.
actually shared_ptr
's destructor is required to do the same:
23.11.2.2.2 shared_ptr destructor [util.smartptr.shared.dest]
— (1.1) If
*this
is empty or shares ownership with anothershared_ptr
instance (use_count() > 1
), there are no side effects.— (1.2) Otherwise, if
*this
owns an object p and a deleter d, d(p) is called.
So relying on smart pointers to perform arbitrary actions at scope exit while passing null pointers is not reliable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With