#include <iostream>
#include <string>
#include <utility>
template <typename Fun> class Guard {
public:
explicit Guard(Fun &&f) : _fun(std::forward<Fun>(f)), _active(true) {}
~Guard() {
if (_active) {
_fun();
}
}
void Dismiss() { _active = false; }
Guard() = delete;
Guard(const Guard &) = delete;
Guard &operator=(const Guard &) = delete;
Guard(Guard &&rhs) : _fun(std::move(rhs._fun)), _active(rhs._active) {
rhs.Dismiss();
}
private:
Fun _fun;
bool _active;
};
enum class GuardOnExit {};
template <typename Fun> inline Guard<Fun> operator+(GuardOnExit, Fun &&fn) {
return Guard<Fun>(std::forward<Fun>(fn));
}
// 自动生成唯一标识符
#define XHL_CAT(s1, s2) s1##s2
#define AUTO_NAME_GEN_(name, line) XHL_CAT(name, line)
#define AUTO_NAME_GEN AUTO_NAME_GEN_(AUTO_NAME_, __LINE__)
// @brief auto guard = MAKE_SG{ fclose(fp);};
#define MAKE_SG GuardOnExit() + [&]()
// @brief ON_SCOPE_EXIT{fclose(fp);};
#define ON_SCOPE_EXIT auto AUTO_NAME_GEN = MAKE_SG
std::string GetResult1() {
std::string result = "";
ON_SCOPE_EXIT { std::cout << "Result1:" << result << std::endl; };
std::string gray_result = "test1";
bool gray = false;
if (gray) {
return gray_result;
}
result = "Result1";
return result;
}
std::string GetResult2() {
std::string result = "";
ON_SCOPE_EXIT { std::cout << "Result2: " << result << std::endl; };
std::string gray_result = "test";
bool gray = false;
if (gray) {
// return gray_result;
}
result = "Result2";
return result;
}
int main() {
std::string result1 = GetResult1();
std::cout << "result1: " << result1 << std::endl;
std::string result2 = GetResult2();
std::cout << "result2: " << result2 << std::endl;
return 0;
}
打印出来的结果
- 为什么GetResult1里面打印不出来result值,但是实际外层调用是有返回这个值的
- GetResult2和GetResult1只相差了return gray_result;,但是GetResult2里面能打印出来result值
Guard 析构发生在 return result; 之后。return result; 使用 result 构造一个新的临时对象作为返回值(result 就析构了,没法返回调用者),而且会尽可能使用 move 而不是 copy 。这里在打印的时候 result 就已经被 move 了。被 move 之后的对象通常会被置空,所以啥也没有了。
而在 GetReresult2 中,由于少了一个 return ,满足了 copy elision 的条件。发生 copy elision 之后,return 处的 copy/move 就不会发生了。
return 会使用其操作数构造一个临时对象作为返回值,局部变量的析构发生在临时对象构造之后。(stmt.jump#stmt.return)
return 一个局部变量会尽可能使用 move ,而不是 copy 。(class.copy.elision#3)
被 move 的对象,其状态时不确定的(通常是会被置空)。(lib.types.movedfrom#1)
GetResult2 由于少了一个 return ,满足了发生 copy elision 的条件,于是本来时“局部”的 result 变量,可以直接使用 main 中的 result2 ,从而省去了一个 copy / move。(class.copy.elision#1.1)