5 ms·
This is not even remotely true. Let's say you have: std::unique_ptr<foo> m_foo; How do you pass that into a function that can receive a pointer to foo, but
by CodeMage 7y ago
This is not even remotely true. Let's say you have:
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.
- Leherenn 7y agoI am not sure I understand what you mean, but now (c++17) you can use an optional in this case.
- paulddraper 7y ago> How do you pass that into a function that can receive a pointer to foo, but does not require it? 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/index.html https://www.boost.org/doc/libs/1_52_0/libs/optional/doc/html... * https://github.com/akrzemi1/Optional https://github.com/akrzemi1/Optional
- deleted 7y ago[deleted]
- jcelerier 7y agostd::optional does not support references (std::optional<MyVeryLargeType&>) however unlike boost, so this precludes usage with non-copyable types.
- paulddraper 7y agoThat was decided against for now, though I'm not sure why. [1] In any case, you can use std::optional<std::reference_wrapper<MyVeryLargeType>>. [1] https://stackoverflow.com/a/26895581 https://stackoverflow.com/a/26895581
- jcelerier 7y ago> 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.
- paulddraper 7y agoIt's hard to tell, but if T* foo can be NULL (and I assume that it can, though there's no visible indication), your first function is gonna segfault. It's easy to tell that in the second function. Second function makes for a better code review.
- jcelerier 7y agoheh, to say that I originally wrote if(foo) and then replaced it by //... because that was not the point. Also, dereferencing an unset optional is also UB, so it would segfault all the same given the same preconditions.
- paulddraper 7y agoYes. The code is equivalent, but it's clear that the second is meant to optional. The first has no such indication, except hopefully some human-readable comment that the pointer may be NULL.
- gumby 7y agoThis is precisely what std::optional is for.
- CodeMage 7y agoI can't edit my original comment anymore, so I'll just write a clarification in the reply. 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.
- jez 7y agoThis is a great reply and I think it echoes what I've seen written elsewhere. For example, this one by Herb Sutter: https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/ https://herbsutter.com/2013/06/05/gotw-91-solution-smart-poi...