16

I've being reading the list of library changes proposed for C++23 and I'm quite curious about the std::out_ptr and std::inout_ptr (their _t siblings). As far as I understand they are some kind of wrapper for smart pointers to be compatible with raw pointers, but I haven't managed to understand them yet. Maybe someone here is familiar with the proposal or may give a less ISO-like explanation or examples?

cbuchart
  • 10,847
  • 9
  • 53
  • 93
  • 4
    I guess the best description you will get is from the [proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1132r8.html) itself. – Timo Aug 25 '21 at 07:18
  • purpose is to use them for C-API which take/set owning pointer (`void foo(SomeType**)` whereas we would expect `std::unique_ptr foo()` C++-API). – Jarod42 Aug 25 '21 at 07:28
  • Also cppreference already contains some text regarding [`std::out_ptr_t`](https://en.cppreference.com/w/cpp/memory/out_ptr_t) and [`std::inout_ptr_t`](https://en.cppreference.com/w/cpp/memory/inout_ptr_t) (the latter is a bit more elaborate and contains an example) – andreee Aug 25 '21 at 07:39

1 Answers1

18

TL;DR - it is for simpler and more seemless interoperability between C out/inout pointer parameters and smart pointers

Longer answer

Let's separate the stuff. std::out_ptr and std::inout_ptr are functions used to create objects of type std::out_ptr_t and std::inout_ptr_t respectively. What are those types and functions for? Let's look at an example inspired by this (for simplicity I replaced generic argument with good ol' int):

int foreign_resetter(int**);
auto up = std::make_unique<int>(5);
 
if (int ec = foreign_resetter(std::inout_ptr(up)) {
    return ec;
}

As you see std::inout_ptr_t created with std::inout_ptr is passed to function taking pointer to pointer to the template argument of std::unique_ptr. Before adding std::inout_ptr_t interoperation with old C in-out pointer parameters was much more cumbersome and error prone. It would look more less like this:

int foreign_resetter(int**);
auto up = std::make_unique<int>(5);
 
int* up_raw = up.release();
if (int ec = foreign_resetter(&up_raw)) {
    return ec;
}
up.reset(up_raw);

Differences out_ptr vs inout_ptr

From the proposal P1132:

inout_ptr's semantics are exactly like out_ptr's, just with the additional requirement that it calls .release() on the smart pointer upon constructing the temporary inout_ptr_t.

This is because the foreign_resetter might delete a pointer before setting a new one, calling .release() reserves that behavior and can be safer. Use inout_ptr if your pointer is already valid and allocated, and out_ptr if the smart pointer is empty.

fen
  • 9,835
  • 5
  • 34
  • 57
bartop
  • 9,971
  • 1
  • 23
  • 54
  • can you also mention what's the difference between `out_ptr` and `inout_ptr`? – fen Mar 22 '23 at 11:57
  • Your cumbersome version is buggy. You leak the object in case of an error. But that's actually easy to fix. The bigger problem is the `inout_ptr` version - it's actually more error-prone, since C APIs often don't guarantee the output is valid in case of an error. So you could end up with a garbage pointer in that case. – user541686 Mar 22 '23 at 14:12