Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VERIFY_RESULT creates undesirable copy of Result<T&>'s value #2298

Closed
d-uspenskiy opened this issue Sep 13, 2019 · 0 comments
Closed

VERIFY_RESULT creates undesirable copy of Result<T&>'s value #2298

d-uspenskiy opened this issue Sep 13, 2019 · 0 comments
Assignees

Comments

@d-uspenskiy
Copy link
Contributor

d-uspenskiy commented Sep 13, 2019

VERIFY_RESULT and similar macros uses GNU expression statement __extension__

#define VERIFY_RESULT(expr) \
  __extension__ ({ auto&& __result = (expr); RETURN_NOT_OK(__result); std::move(*__result); })

In spite of the fact last statement is a rvalue copy object is created by using of T(T&&) move-constructor (if any) for Result<T>/Result<T&> situation and T::T(const T&) copy-constructor (if any) for Result<const T&>

This behavior produces several undesirable side effects of using VERIFY_RESULT:

  • can't be used for functions/methods which returns Result with non-copyable T even in Result<T&>/Result<const T&> form
  • In case T is moveable returning of Result<T&> from function/method original object of T will be set to unspecified state
Result<vector<int>&> GetData() {
   return data_;
} 

simple calling of VERIFY_RESULT(obj.GetData()) will set obj's data_ field to unspecified state (state of moved from object)

  • In case T is copyable but not moveable returning of Result<T&>/Result<const T&> creates undesirable copy of T
Result<const map<string, string>&> GetLargeData() const {
  return data_;
}

each call of VERIFY_RESULT(obj.GetLargeData()) will create map's copy

@d-uspenskiy d-uspenskiy self-assigned this Sep 13, 2019
@d-uspenskiy d-uspenskiy changed the title VERIFY_RESULT creates undesirable copy of Result value VERIFY_RESULT creates undesirable copy of Result<T&>'s value Sep 13, 2019
d-uspenskiy added a commit that referenced this issue Sep 19, 2019
Summary:
1. `VERIFY_RESULT` and similar macros uses GNU expression statement `__extension__`

```
#define VERIFY_RESULT(expr) \
  __extension__ ({ auto&& __result = (expr); RETURN_NOT_OK(__result); std::move(*__result); })
```

In spite of the fact last statement is a rvalue reference copy object is created by using of `T(T&&)` move-constructor (if any) for `Result<T>/Result<T&>` situation and `T::T(const T&)` copy-constructor (if any) for `Result<const T&>`

To avoid undesirable copying of `T` object in case of `Result<T&>` and `Result<const T&>` `std::reference_wrapper<T>` is returned from expression statement `__extension__`.
As of now `VERIFY_RESULT` and similar macros returns `std::reference_wrapper<T>` for `Result<T&>/Result<const T&>` situation new helper macro `VERIFY_RESULT_REF` is introduced (it is still safe to use `VERIFY_RESULT` in this situation).

It is useful with `auto`:
```
Result<const vector<int>&> GetVector() {
  static const vector<int> values{1, 2, 3};
  return values;
}

const auto& value = VERIFY_RESULT_REF(GetVector());
...
for(const auto& i : VERIFY_RESULT_REF(GetVector())) {
...
}
```

2. Make `Status::OK()` be a wrapper to avoid creation of `Result<T>` from it at compile time

Test Plan:
New unit test was introduced
```
./yb_build.sh --cxx-test result-test
```

Reviewers: mikhail, sergei

Reviewed By: sergei

Subscribers: bogdan, ybase

Differential Revision: https://phabricator.dev.yugabyte.com/D7204
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant