c++17引入的函数介绍 std::launder
27 Apr 2019
|
|
why
在semimap的ppt里见到了std::launder,一个c++17引入的函数,学习了解一下
看提案就能大概了解std::launder到底是为了啥,解决掉placement new和reinterpret_cast在const场景下带来的未定义行为,比如这个例子
struct X { const int n; };
union U { X x; float f; };
void tong() {
U u = 1;
u.f = 5.f; // OK, creates new subobject of 'u'
X *p = new (&u.x) X {2}; // OK, creates new subobject of 'u'
assert(p->n == 2); // OK
assert(*std::launder(&u.x.n) == 2); // OK
// undefined behavior, 'u.x' does not name new subobject
assert(u.x.n == 2);
}
如果内部有const,可能编译器会优化掉访问值的行为,std::launder就是为了解决掉这个场景,阻止编译器优化
std::launder
acts as an optimization barrier that prevents the optimizer from performing constant propagation.
实现,就是一层阻止优化的封装,参考链接3中详细列举了gcc实现以及相应的问题
folly的实现见参考链接5,因为是应用,就封装了一层
template <typename T>
FOLLY_NODISCARD inline T* launder(T* in) noexcept {
#if FOLLY_HAS_BUILTIN(__builtin_launder) || __GNUC__ >= 7
// The builtin has no unwanted side-effects.
return __builtin_launder(in);
#elif __GNUC__
// This inline assembler block declares that `in` is an input and an output,
// so the compiler has to assume that it has been changed inside the block.
__asm__("" : "+r"(in));
return in;
#elif defined(_WIN32)
// MSVC does not currently have optimizations around const members of structs.
// _ReadWriteBarrier() will prevent compiler reordering memory accesses.
_ReadWriteBarrier();
return in;
#else
static_assert(
false, "folly::launder is not implemented for this environment");
#endif
}
对于gcc环境,看asm那条就懂了,优化让他强制访问地址而不是读const
llvm的实现见参考链接6,比较复杂,就不列代码了
reference
- 提案http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0532r0.pdf
- https://zh.cppreference.com/w/cpp/utility/launder 翻译的偏学术,结合例子看更佳
- 这个博客讲的很好https://miyuki.github.io/2016/10/21/std-launder.html
- 其中涉猎的很多链接我都是先看了一遍,才搜到这个博客。。走了点弯路
- 我也搜了launder的实现,结果发现这个博客已经列举了。
- 上面的博客援引的链接 ,也是用的同样的实例https://stackoverflow.com/questions/39382501/what-is-the-purpose-of-stdlaunder
- folly的实现 https://github.com/facebook/folly/blob/master/folly/lang/Launder.h
- llvm的实现https://reviews.llvm.org/D40218