代码之家  ›  专栏  ›  技术社区  ›  Anycorn

C++静态初始化

  •  3
  • Anycorn  · 技术社区  · 15 年前

    在下列情况下,应该是什么行为:

    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? 
        ....
    }
    

    是否允许编译器优化对的调用 get() ?

    这是更好的选择吗?:

    C& get() {
        static C *c = new C();
        return *c;
    }
    
    3 回复  |  直到 15 年前
        1
  •  4
  •   Jerry Coffin    15 年前

    我看不出一种方法可以让一致性代码区分 get 在本例中实际调用了,所以在我看来,它可以自由地进行优化。

        2
  •  3
  •   SingleNegationElimination    15 年前

    输入:

    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? 
    
    }
    

    输出:

    ; 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
    }
    

    值得注意的是,没有为::get发出代码,但main仍然根据需要(在%2和invcont.i和lpad.i的末尾)使用保护变量分配::get::c(在%4)。llvm在这里内联所有这些东西。

        3
  •  1
  •   Chubsdad    15 年前

    编译器是否优化函数调用基本上是标准中未指定的行为。未指定的行为基本上是从一组有限的可能性中选择的行为,但是选择可能不是每次都一致的。在这种情况下,选择是“优化”还是“不优化”,这是标准没有规定的,实现也不应该记录,因为这是一个给定实现可能不一致地采取的选择。

    例如

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