通过 "std::lock_guard<mutex>" 引用 return 共享对象安全吗?
Is it safe to return a shared object by reference with "std::lock_guard<mutex>"?
#include <vector>
#include <string>
#include <mutex>
#include <future>
using namespace std;
mutex g_mtx;
vector<string> g_coll;
void Cleaner()
{
lock_guard<mutex> lock(g_mtx);
g_coll.clear();
}
const vector<string>& Getter()
{
lock_guard<mutex> lock(g_mtx);
return g_coll;
}
int main()
{
g_coll = { "hello" };
auto fut = async([&]()
{
Cleaner();
});
auto returned_coll = Getter();
fut.get();
}
如果Cleaner
在return g_coll;
之后执行,C++标准是否保证returned_coll
包含{ "hello" }
?
不,这不安全。
语义上,non-voidreturn类型returns的函数事件顺序如下:
- 计算 return 语句中的表达式。
- return 值是来自所述表达式的 copy-initialized。
- 自动局部变量按构造的相反顺序销毁。
- 控制 return 给调用者。
请注意 returned_coll
不是 return 值。相反,Getter()
是 return 值。 Getter()
从左值 return 对 returned_coll
的初始化发生在步骤 4 之后。
因此,当returned_coll
从Getter()
变为copy-initialized时,Getter
持有的mutex已经被释放,也就是说[=10=的初始化] 可能会与 Cleaner
.
中的访问竞争
#include <vector>
#include <string>
#include <mutex>
#include <future>
using namespace std;
mutex g_mtx;
vector<string> g_coll;
void Cleaner()
{
lock_guard<mutex> lock(g_mtx);
g_coll.clear();
}
const vector<string>& Getter()
{
lock_guard<mutex> lock(g_mtx);
return g_coll;
}
int main()
{
g_coll = { "hello" };
auto fut = async([&]()
{
Cleaner();
});
auto returned_coll = Getter();
fut.get();
}
如果Cleaner
在return g_coll;
之后执行,C++标准是否保证returned_coll
包含{ "hello" }
?
不,这不安全。
语义上,non-voidreturn类型returns的函数事件顺序如下:
- 计算 return 语句中的表达式。
- return 值是来自所述表达式的 copy-initialized。
- 自动局部变量按构造的相反顺序销毁。
- 控制 return 给调用者。
请注意 returned_coll
不是 return 值。相反,Getter()
是 return 值。 Getter()
从左值 return 对 returned_coll
的初始化发生在步骤 4 之后。
因此,当returned_coll
从Getter()
变为copy-initialized时,Getter
持有的mutex已经被释放,也就是说[=10=的初始化] 可能会与 Cleaner
.