简体   繁体   English

C ++静态初始化

[英]C++ static initialization

what should be the behavior in the following case: 在下列情况下应该是什么行为:

class C {
    boost::mutex mutex_;
    std::map<...> data_;
};

C& get() {
    static C c;
    return c;
}

int main() {
    get(); // is compiler free to optimize out the call? 
    ....
}

is compiler allowed to optimize out the call to get() ? 编译器是否允许优化调用get()

the idea was to touch static variable to initialize it before multithreaded operations needed it 我的想法是在多线程操作需要之前触摸静态变量来初始化它

is this a better option?: 这是一个更好的选择吗?:

C& get() {
    static C *c = new C();
    return *c;
}

The C and C++ standards operate under a rather simple principle generally known as the "as-if rule" -- basically, that the compiler is free to do almost anything as long as no conforming code can discern the difference between what it did and what was officially required. C和C ++标准在一个相当简单的原则下运行,通常被称为“as-if规则” - 基本上,只要没有符合规范的代码能够辨别它做了什么和做什么之间的差异,编译器就可以自由地做任何事情。是正式要求的。

I don't see a way for conforming code to discern whether get was actually called in this case, so it looks to me like it's free to optimize it out. 我没有看到符合代码的方法来辨别在这种情况下是否实际调用了get ,所以在我看来它可以自由地优化它。

Based on your edits, here's an improved version, with the same results. 根据您的编辑,这是一个改进的版本,具有相同的结果。

Input: 输入:

struct C { 
    int myfrob;
    int frob();
    C(int f);
 };
C::C(int f) : myfrob(f) {}
int C::frob() { return myfrob; }

C& get() {
    static C *c = new C(5);
    return *c;
}

int main() {
    return get().frob(); // is compiler free to optimize out the call? 

}

Output: 输出:

; ModuleID = '/tmp/webcompile/_28088_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-linux-gnu"

%struct.C = type { i32 }

@guard variable for get()::c = internal global i64 0            ; <i64*> [#uses=4]

declare i32 @__cxa_guard_acquire(i64*) nounwind

declare i8* @operator new(unsigned long)(i64)

declare void @__cxa_guard_release(i64*) nounwind

declare i8* @llvm.eh.exception() nounwind readonly

declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind

declare void @__cxa_guard_abort(i64*) nounwind

declare i32 @__gxx_personality_v0(...)

declare void @_Unwind_Resume_or_Rethrow(i8*)

define i32 @main() {
entry:
  %0 = load i8* bitcast (i64* @guard variable for get()::c to i8*), align 8 ; <i8> [#uses=1]
  %1 = icmp eq i8 %0, 0                           ; <i1> [#uses=1]
  br i1 %1, label %bb.i, label %_Z3getv.exit

bb.i:                                             ; preds = %entry
  %2 = tail call i32 @__cxa_guard_acquire(i64* @guard variable for get()::c) nounwind ; <i32> [#uses=1]
  %3 = icmp eq i32 %2, 0                          ; <i1> [#uses=1]
  br i1 %3, label %_Z3getv.exit, label %bb1.i

bb1.i:                                            ; preds = %bb.i
  %4 = invoke i8* @operator new(unsigned long)(i64 4)
          to label %invcont.i unwind label %lpad.i ; <i8*> [#uses=2]

invcont.i:                                        ; preds = %bb1.i
  %5 = bitcast i8* %4 to %struct.C*               ; <%struct.C*> [#uses=1]
  %6 = bitcast i8* %4 to i32*                     ; <i32*> [#uses=1]
  store i32 5, i32* %6, align 4
  tail call void @__cxa_guard_release(i64* @guard variable for get()::c) nounwind
  br label %_Z3getv.exit

lpad.i:                                           ; preds = %bb1.i
  %eh_ptr.i = tail call i8* @llvm.eh.exception()  ; <i8*> [#uses=2]
  %eh_select12.i = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %eh_ptr.i, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null) ; <i32> [#uses=0]
  tail call void @__cxa_guard_abort(i64* @guard variable for get()::c) nounwind
  tail call void @_Unwind_Resume_or_Rethrow(i8* %eh_ptr.i)
  unreachable

_Z3getv.exit:                                     ; preds = %invcont.i, %bb.i, %entry
  %_ZZ3getvE1c.0 = phi %struct.C* [ null, %bb.i ], [ %5, %invcont.i ], [ null, %entry ] ; <%struct.C*> [#uses=1]
  %7 = getelementptr inbounds %struct.C* %_ZZ3getvE1c.0, i64 0, i32 0 ; <i32*> [#uses=1]
  %8 = load i32* %7, align 4                      ; <i32> [#uses=1]
  ret i32 %8
}

Noteworth, no code is emitted for ::get, but main still allocates ::get::c (at %4) with a guard variable as needed (at %2 and at the end of invcont.i and lpad.i). 注意,没有为:: get发出代码,但是main仍然根据需要使用保护变量分配:: get :: c(at%4)(在%2和invcont.i和lpad.i的末尾)。 llvm here is inlining all of that stuff. llvm这里列出了所有这些东西。

tl;dr: Don't worry about it, the optimizer normally gets this stuff right. tl; dr:不要担心,优化器通常会正确地获取这些东西。 Are you seeing an error? 你看到错误了吗?

Whether the compiler optimizes the function call or not is basically unspecified behavior as per the Standard. 编译器是否优化函数调用基本上是未指定的行为,根据标准。 An unspecified behavior is basically a behavior which is chosen from a set of finite possibilities, but the choice may not be consistent every time. 未指定的行为基本上是从一组有限可能性中选择的行为,但是每次选择可能不一致。 In this case, the choice is 'to optimize' or 'not', which the Standard does not specify and the implementation is also not supposed to document, as it is a choice which may not be consistently taken by a given implementation. 在这种情况下,选择是'优化'或'不',标准没有指定,并且实现也不应该记录,因为它是给定实现可能不一致采用的选择。

If the idea is just to 'touch', will it help if we just add a dummy volatile variable and dummy increment it in each call 如果想法只是“触摸”,如果我们只是在每个调用中添加一个虚拟的volatile变量并且虚拟递增它,它会有所帮助

eg 例如

C& getC(){
   volatile int dummy;
   dummy++;
   // rest of the code
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM