diff --git a/src/butil/endpoint.cpp b/src/butil/endpoint.cpp index ac1f958ceb..cfd536a06f 100644 --- a/src/butil/endpoint.cpp +++ b/src/butil/endpoint.cpp @@ -467,11 +467,11 @@ int pthread_timed_connect(int sockfd, const struct sockaddr* serv_addr, butil::make_non_blocking(sockfd); } // Scoped non-blocking. - auto guard = butil::MakeScopeGuard([is_blocking, sockfd]() { + BRPC_SCOPE_EXIT { if (is_blocking) { butil::make_blocking(sockfd); } - }); + }; const int rc = ::connect(sockfd, serv_addr, addrlen); if (rc == 0 || errno != EINPROGRESS) { diff --git a/src/butil/memory/scope_guard.h b/src/butil/memory/scope_guard.h index 1771683f68..5ed65a4ce9 100644 --- a/src/butil/memory/scope_guard.h +++ b/src/butil/memory/scope_guard.h @@ -19,6 +19,7 @@ #define BRPC_SCOPED_GUARD_H #include +#include "butil/macros.h" namespace butil { @@ -83,6 +84,31 @@ ScopeGuard MakeScopeGuard(Callback&& callback) noexcept { return ScopeGuard{ std::forward(callback)}; } +namespace internal { +// for BAIDU_SCOPE_EXIT. +enum class ScopeExitHelper {}; + +template +ScopeGuard +operator+(ScopeExitHelper, Callback&& callback) { + return MakeScopeGuard(std::forward(callback)); } +} // namespace internal +} // namespace butil + +#define BRPC_ANONYMOUS_VARIABLE(prefix) BAIDU_CONCAT(prefix, __COUNTER__) + +// The code in the braces of BAIDU_SCOPE_EXIT always executes at the end of the scope. +// Variables used within BAIDU_SCOPE_EXIT are captured by reference. +// Example: +// int fd = open(...); +// BAIDU_SCOPE_EXIT { +// close(fd); +// }; +// use fd ... +// +#define BRPC_SCOPE_EXIT \ + auto BRPC_ANONYMOUS_VARIABLE(SCOPE_EXIT) = \ + ::butil::internal::ScopeExitHelper() + [&]() noexcept #endif // BRPC_SCOPED_GUARD_H diff --git a/test/scope_guard_unittest.cc b/test/scope_guard_unittest.cc index 085162fdff..f5e4b620d3 100644 --- a/test/scope_guard_unittest.cc +++ b/test/scope_guard_unittest.cc @@ -28,6 +28,25 @@ TEST(ScopedGuardTest, sanity) { } ASSERT_TRUE(flag); + flag = false; + { + BRPC_SCOPE_EXIT { + flag = true; + }; + } + ASSERT_TRUE(flag); + + { + BRPC_SCOPE_EXIT { + flag = true; + }; + + BRPC_SCOPE_EXIT { + flag = false; + }; + } + ASSERT_TRUE(flag); + flag = false; { auto guard = butil::MakeScopeGuard([&flag] {