From 8deb28b372c8a435aa2a9f0d7977332f500f9fee Mon Sep 17 00:00:00 2001 From: Anand Mazumdar Date: Mon, 29 Aug 2016 23:21:40 -0700 Subject: [PATCH] Modified ref-qualifiers return type for Optional::value() and Optional::operator* Summary: Optional::value() returns a temporary object when the object is an rvalue. This is different in semantics then what boost::optional/std::optional do. The decision to make the copy or not should be up to the user and not the library. Consider an example: ``` void F(Optional &&opt) { T&& t = std::move(opt).get(); // I know `opt` is alive in this scope, I should be able to keep a rvalue ref to the internals } // if we were to return a `T`, that would actually return a new temporary. ``` ``` void G(T&& t); G(std::move(opt).get()); // This could have surprising behavior too ! ``` This change modified the return type to be `T&&` and also introduces an extra overload for `const T&&`. Also, deleted two test-cases that assume the lifetime to be extended. This is a breaking change but this brings folly::Optional on parity with other siblings. Closes https://github.com/facebook/folly/pull/353 Reviewed By: ddrcoder Differential Revision: D3714962 Pulled By: yfeldblum fbshipit-source-id: 1794d51590062db4ad02fc8688cb28a06712c076 --- folly/Optional.h | 20 ++++++++++---------- folly/test/OptionalTest.cpp | 14 -------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/folly/Optional.h b/folly/Optional.h index 2b12ccc6..e897c38b 100644 --- a/folly/Optional.h +++ b/folly/Optional.h @@ -206,10 +206,12 @@ class Optional { return storage_.value; } - // TODO: This should return Value&& instead of Value. Like with - // std::move, the calling code should decide whether it wants the move - // to happen or not. See std::optional. - Value value() && { + Value&& value() && { + require_value(); + return std::move(storage_.value); + } + + const Value&& value() const&& { require_value(); return std::move(storage_.value); } @@ -228,12 +230,10 @@ class Optional { return hasValue(); } - const Value& operator*() const& { return value(); } - Value& operator*() & { return value(); } - // TODO: This should return Value&& instead of Value. Like with - // std::move, the calling code should decide whether it wants the move - // to happen or not. See std::optional. - Value operator*() && { return std::move(value()); } + const Value& operator*() const& { return value(); } + Value& operator*() & { return value(); } + const Value&& operator*() const&& { return std::move(value()); } + Value&& operator*() && { return std::move(value()); } const Value* operator->() const { return &value(); } Value* operator->() { return &value(); } diff --git a/folly/test/OptionalTest.cpp b/folly/test/OptionalTest.cpp index 1082b35b..0fc31e0b 100644 --- a/folly/test/OptionalTest.cpp +++ b/folly/test/OptionalTest.cpp @@ -174,26 +174,12 @@ struct ExpectingDeleter { } }; -TEST(Optional, value_life_extention) { - // Extends the life of the value. - const auto& ptr = Optional>( - {new int(42), ExpectingDeleter{1337}}).value(); - *ptr = 1337; -} - TEST(Optional, value_move) { auto ptr = Optional>( {new int(42), ExpectingDeleter{1337}}).value(); *ptr = 1337; } -TEST(Optional, dereference_life_extention) { - // Extends the life of the value. - const auto& ptr = *Optional>( - {new int(42), ExpectingDeleter{1337}}); - *ptr = 1337; -} - TEST(Optional, dereference_move) { auto ptr = *Optional>( {new int(42), ExpectingDeleter{1337}}); -- 2.34.1