std::unique_ptr<foo> m_foo;
How do you pass that into a function that can receive a pointer to foo, but does not require it? The only way to do so is to declare the function to take a foo* and pass it m_foo.get()In summary, * will never be deprecated until C++ has support for something along the lines of Rust's borrowing and lifetimes.
Many people have pointed out that C++17 has std::optional. While that's true, I don't think it'll deprecate raw pointers. I'll try to explain why.
Here's an example you can paste, compile and run:
#include <iostream>
#include <memory>
struct foo
{
int thingamajig;
};
void borrow_optional_foo(foo * borrowed)
{
if (borrowed != nullptr)
{
borrowed->thingamajig = 42;
}
}
int main()
{
std::unique_ptr<foo> owned = std::make_unique<foo>();
owned->thingamajig = 17;
std::cout << owned->thingamajig << std::endl;
borrow_optional_foo(owned.get());
std::cout << owned->thingamajig << std::endl;
return 0;
}
If you run it, it should print: 17
42
What would it look like if we wanted to use std::optional and get the same behavior? #include <iostream>
#include <functional>
#include <memory>
#include <optional>
struct foo
{
int thingamajig;
};
void borrow_optional_foo(std::optional<std::reference_wrapper<foo>> borrowed)
{
if (borrowed)
{
borrowed->get().thingamajig = 42;
}
}
int main()
{
std::unique_ptr<foo> owned = std::make_unique<foo>();
owned->thingamajig = 17;
std::cout << owned->thingamajig << std::endl;
borrow_optional_foo(std::make_optional(std::ref(*(owned.get()))));
std::cout << owned->thingamajig << std::endl;
return 0;
}
As you can see, there's a tradeoff involved. On the one hand, you get crystal clear, descriptive type: std::optional<std::reference_wrapper<foo>> is clearly an optional reference to foo.On the other hand, using it is absolutely atrocious: you have to write borrowed->get().thingamajig as opposed to borrowed->thingamajig, and std::make_optional(std::ref(*(owned.get()))) as opposed to owned.get()
Does it work? Absolutely. Is it crystal clear? Indisputably so. Will it deprecate raw pointers? I really, really doubt it, but that's just my opinion.
https://herbsutter.com/2013/06/05/gotw-91-solution-smart-poi...
Same as you would have a function that can receive an `int` but does not require it. Or a receive a `std::vector` but does not require it.
I surmise that you mean "how do you pass any value (pointer or otherwise) into a function that can receive a value but does require it". And I surmise you have before used pointer indirection to pass that value because it has a conventional sentinel value of 0/NULL/nullptr.
You are correct in that optional values did not have a standardized solution, until C++17 std::optional.
If you don't have C++17, I recommend one of the equivalent third-party implementations:
* https://www.boost.org/doc/libs/1_52_0/libs/optional/doc/html...
In any case, you can use std::optional<std::reference_wrapper<MyVeryLargeType>>.
I would frankly give a negative code review to anyone who would do that.
You go from e.g.
void my_function(T* foo, T* bar, int baz)
{
// ...
foo->stuff(bar, baz);
}
to void my_function(std::optional<std::reference_wrapper<T>> foo, std::optional<std::reference_wrapper<T>> bar, int baz)
{
// ...
foo->get().call(&bar->get(), z);
}
this also has more overhead (sizeof(std::optional<std::reference_wrapper<T>>) is twice the size of T* ),
and let's not even start talking about calling conventions and the compile time cost of having to include both <functional> and <optional> everywhere.It's easy to tell that in the second function.
Second function makes for a better code review.
The first has no such indication, except hopefully some human-readable comment that the pointer may be NULL.
I don't understand. If the parameter was not meant to be sometimes null it would be a reference; not a pointer. The fact that a pointer is used is the "this may be null" indication.
But C++ is a systems programming language and * is still quite useful.