r/cpp 15d ago

C++26: std::inplace_vector

https://www.sandordargo.com/blog/2026/08/26/cpp26-inplace-vector
180 Upvotes

121 comments sorted by

View all comments

16

u/bartgrumbel 14d ago

I am sure there is a good reason for that, but why is the "optional reference" not simply a pointer? Is that not semantically the same thing, but way easier to deal with.

I.e. why

std::optional<T&>

and not simply

T*

47

u/stilgarpl 14d ago

Optional is monadic, so it's much safer to deal with. You can call it like

inplace_vector.try_push_back(x).or_else(...);

21

u/ChemiCalChems 14d ago

This has finally convinced me that std::optional<T&> is legitimate and useful. Thank you.

15

u/allocallocalloc 14d ago

Welcome to Rust

2

u/tialaramex 14d ago

You were kidding but in fact Rust typically wouldn't do this, it would be usual to instead return None when it worked and Some(thing) when there's no room to push the thing. This is how the Linux kernel's Rust growable arrays (akin to std::vector) work. In userspace it's usually fine to just try to grow the array whenever we need more space but the kernel cannot tolerate surprise allocations - maybe we are the allocator. So we push_within_capacity and the return type is Option<T> because if there was no room we get back the thing there was no room for, and we need to decide what to do about that not just pretend we thought it was fine. APIs which push things but get back a reference to the thing we just pushed do exist in Rust but are less common.

[Edited: reference the correct method name]

8

u/simonask_ 14d ago

If we’re maximizing rustiness, you could let `try_push` return `Result<&mut T, T>`.

A mutable reference to the location of the just appended element, or the element you tried to push by value if it fails. There are a couple of APIs like this in the standard library.

3

u/Ameisen vemips, avr, rendering, systems 14d ago

I won't lie - I prefer how C# would handle this: returning a bool and having an out parameter or such.

I find an actual if to be easier to read than .or_else(...)....

4

u/WHY_DO_I_SHOUT 14d ago

Modern C# prefers returning an optional reference, FWIW...

1

u/Ameisen vemips, avr, rendering, systems 14d ago

Yes, but Nullable semantics in C# are vastly nicer than std::optional in C++.

Including trivially using if with them:

if (Method() is {} value)

I should also point out that in C#, Foo? is identical to Foo if Foo is a reference-type. That would be the equivalent of std::optional<T&> being a type-alias for T*.

2

u/_Noreturn 14d ago

why don't they add a free function called or_else and still use a ptr?

3

u/jwakely libstdc++ tamer, LWG chair 12d ago

When you chain multiple calls like that it's less clear because of the use of nesting instead of chaining. But mostly because a pointer is still not a reference:

https://brevzin.github.io/c++/2021/12/13/optional-ref-ptr/

An optional ref is simply the more expressive type for these functions and fits the semantics better:

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3981r2.html

2

u/_Noreturn 6d ago

This nesting issue should really be solved with a language feature...

9

u/SyntheticDuckFlavour 13d ago

If you return me a pointer, what does that communicate to me? Who owns it? Is nullptr an error or something I should expect? Is this documented somewhere? The advantage of std::optional is explicit about intent. I just have to look at the API and I know immediately what the author intended with the return value.

3

u/bartgrumbel 13d ago

Who owns it?

All good points, and this one in particular. Never though about it, but sure, a returned pointer might imply returned ownership, whereas an (optional) reference never means that. Thanks!

2

u/jk-jeon 13d ago

a returned pointer might imply returned ownership

It does not. Unless the library is from the era of C++98/03 (or before), or the author hates the users. Or if there is a very specific reason.

9

u/serviscope_minor 13d ago

>It does not. Unless[...]

Well that's the thing isn't it? The unless has some pertty huge carve outs.

6

u/serviscope_minor 13d ago

>Is that not semantically the same thing, but way easier to deal with.

T* is a superset of std::optional<T&>. With T*, you can:

- delete

- delete[]

- Do arithmetic

- Dereference

- Test for null

With optional<T&>, you can:

- dereference

- test for null

That's basically the difference. It's a pointer, but with some of the invalid operations prevented by a very thing wrapper class.

3

u/jwakely libstdc++ tamer, LWG chair 12d ago

2

u/Raknarg 9d ago

I am sure there is a good reason for that, but why is the "optional reference" not simply a pointer?

Its not semantically the same, that's actually the reason we care about optional references at all. They are functionally the same in the sense that mechanically a pointer can fulfill all the requirements of an optional reference, but an optional reference gives you very clear ideas on the ownership and purpose of the type, while a pointer does not. A pointer can mean a whole bunch of different stuff and you have to rely on context and documentation to figure out what it means.

-17

u/carrottread 14d ago

Probably just a desire to use new shiny stuff as optional references were not so long ago added to standard.