[C++ Weekly] EP2 Cost of Using Statics
Posted 鱼竿钓鱼干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C++ Weekly] EP2 Cost of Using Statics相关的知识,希望对你有一定的参考价值。
[C++ Weekly] EP2 Cost of Using Statics
C++ 11 为了确保 static 初始化线程安全,存在一定开销
#include <string>
#include <algorithm>
struct C
static const std::string &magic_static()
static const std::string s = "bob";
return s;
const std::string &s = magic_static();
const std::string &magic_static_ref()
return s;
;
auto main() -> int
/*
C::magic_static().size();
C::magic_static().size();
C::magic_static().size();
return C::magic_static().size();
*/
C c;
c.magic_static_ref().size();
c.magic_static_ref().size();
c.magic_static_ref().size();
return c.magic_static_ref().size();
- 我们创建了一个名为“C”的简单结构,在这个结构中,我们有一个使用“首次使用时构造”习语创建的静态,所以这个静态并不真正存在。 直到第一次调用这个 ‘magic_static’ 函数时才构造字符串’S’。
- C++ 11 保证了静态变量的初始化以线程安全的方式进行。
magic_static_ref
不是static
,所以返回的是成员变量s
的引用而不是对静态变量的引用
编译器视角
用 C++ Insights
看 struct C
struct C
static inline const std::basic_string<char, std::char_traits<char>, std::allocator<char> > & magic_static()
static uint64_t __sGuard;
alignas(const std::basic_string<char, std::char_traits<char>, std::allocator<char> >) static char __s[sizeof(const std::basic_string<char, std::char_traits<char>, std::allocator<char> >)];
if( ! __sGuard )
if( __cxa_guard_acquire(&__sGuard) )
try
new (&__s) std::basic_string<char, std::char_traits<char>, std::allocator<char> >("bob", std::allocator<char>());
__sGuard = true;
catch(...)
__cxa_guard_abort(&__sGuard);
throw;
__cxa_guard_release(&__sGuard);
return *reinterpret_cast<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >*>(__s);
const std::basic_string<char, std::char_traits<char>, std::allocator<char> > & s = magic_static();
inline const std::basic_string<char, std::char_traits<char>, std::allocator<char> > & magic_static_ref()
return this->s;
;
可以看到为了保证 static 初始化线程安全有一个类似双检查锁的动作,这会带来一定开销
汇编层面
magic_static
C::magic_static[abi:cxx11](): # @C::magic_static[abi:cxx11]()
push rbp
mov rbp, rsp
sub rsp, 32
cmp byte ptr [rip + guard variable for C::magic_static[abi:cxx11]()::s[abi:cxx11]], 0
jne .LBB1_4
lea rdi, [rip + guard variable for C::magic_static[abi:cxx11]()::s[abi:cxx11]]
call __cxa_guard_acquire@PLT
cmp eax, 0
je .LBB1_4
lea rdi, [rbp - 8]
mov qword ptr [rbp - 32], rdi # 8-byte Spill
call std::allocator<char>::allocator()@PLT
mov rdx, qword ptr [rbp - 32] # 8-byte Reload
lea rdi, [rip + C::magic_static[abi:cxx11]()::s[abi:cxx11]]
lea rsi, [rip + .L.str]
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&)
jmp .LBB1_3
magic_static_ref
C::magic_static_ref[abi:cxx11](): # @C::magic_static_ref[abi:cxx11]()
push rbp
mov rbp, rsp
mov qword ptr [rbp - 8], rdi
mov rax, qword ptr [rbp - 8]
mov rax, qword ptr [rax]
pop rbp
ret
Quick C++ Benchmarks
https://www.quick-bench.com/
#include <string>
#include <algorithm>
#include <benchmark/benchmark.h>
struct C
static const std::string &magic_static()
static const std::string s = "bob";
return s;
const std::string &s = magic_static();
const std::string &magic_static_ref()
return s;
;
static void BM_MAGIC_STATIC_REF(benchmark::State& state)
C c;
for (auto _ : state)
for(int i = 0; i < 1'000'000'000; ++i)
c.magic_static_ref().size();
// Register the function as a benchmark
BENCHMARK(BM_MAGIC_STATIC_REF);
// Define another benchmark
static void BM_MAGIC_STATIC(benchmark::State& state)
for (auto _ : state)
for(int i = 0; i < 1'000'000'000; ++i)
C::magic_static().size();
// Register the function as a benchmark
BENCHMARK(BM_MAGIC_STATIC);
O0
:magic_static_ref
慢于magic_static
O1 ~ O3
:magic_static_ref
直接被编译器优化掉了
O0
O1
O2
O3
以上是关于[C++ Weekly] EP2 Cost of Using Statics的主要内容,如果未能解决你的问题,请参考以下文章
834. Sum of Distances in Tree —— weekly contest 84
128th LeetCode Weekly Contest Complement of Base 10 Integer
123th LeetCode Weekly Contest Add to Array-Form of Integer