2012-02-21 2 views
2

, 이것은 거의 최적의 코드 생성 결과왜 BOOST_FOREACH는 수작업 코드와 정확히 일치하지 않습니까? <a href="http://www.boost.org/doc/libs/1_48_0/doc/html/foreach.html#foreach.introduction.what_is__literal_boost_foreach__literal__" rel="nofollow">boost doc</a> 가입일

; BOOST_FOREACH의 성능은 보통 수작업 코드 루프의 몇 퍼센트 이내입니다.

매크로와 비표준 typeof 연산자를 사용하면 정확하게 동일한 것을 생성 할 수 있습니다. BOOST_FOREACH의 어떤 기능이 정확하지 않습니까?

편집 :

내 버전 : 나는 오버 헤드없이 버전을 쓰기 위해 노력하고 있어요

#define EACH(it,v) \ 
     for(typeof(v.begin()) it = v.begin();it != v.end(); ++it) 

//use this if you want a const_iterator from a non-const container 

    #define CONST_EACH(it,v) \ 
     typedef typeof(v) v_type; \ 
     typedef const v_type& const_type; \ 
     for(typeof(static_cast<const_type>(v).begin()) it = static_cast<const_type>(v).begin(); it != static_cast<const_type>(v).end(); ++it) 

. 이것은 비표준 typeof를 사용하고 value_type 대신 iterator를 제공합니다. 내가 여기서 아무것도 놓치고 있니?

+0

사이드 노트에서'typeof' 연산자는 이식 가능하지 않습니다. – fredoverflow

+2

휴대용이 아니라는 것은 무엇입니까? 나는 이것이 표준의 일부가 아니라는 것을 안다. – balki

+0

나는 옵티 마이저가 그 진술을 따라 잡았다 고 생각한다. BOOST_FOREACH를 사용하는 코드를 벤치마킹하여 동등한 for 루프를 사용하여 좀 더 성능을 끌어낼 수 있는지 확인했습니다. BOOST_FOREACH 코드가 조금 더 빨랐습니다 (즉, 아마도 오차 범위 내에있을 것입니다). – Ferruccio

답변

1

는 I 믿어 BOOST_FOREACH 개체의 불필요한 복사를 생성 할 수있다 천연 루프 구문을 지원하기 위해 채용 책략 일부있다.

5

부스트 foreach는 사소한 것입니다. GCC 4.6 :

int main() 
{ 
    std::string hello("Hello, world!"); 
    BOOST_FOREACH(char ch, hello) 
    { 
     std::cout << ch; 
    } 
    return 0; 
} 

A?B:C으로 탐색 할 경우 많이 발생한다.

int main() 
{ 
    std::string hello("Hello, world!"); 

    if (
boost::foreach_detail_::auto_any_t _foreach_col9 = 
boost::foreach_detail_::contain((hello) , (true ? 0 : 
boost::foreach_detail_::or_( 
boost::foreach_detail_::and_( 
boost::foreach_detail_::not_(
boost::foreach_detail_::is_array_(hello)) , (true ? 0 : 
boost::foreach_detail_::is_rvalue_((true ? 
boost::foreach_detail_::make_probe(hello) : (hello)), 0))) , 
boost::foreach_detail_::and_( 
boost::foreach_detail_::not_(boost_foreach_is_noncopyable( 
boost::foreach_detail_::to_ptr(hello) , boost_foreach_argument_dependent_lookup_hack_value)) , boost_foreach_is_lightweight_proxy( 
boost::foreach_detail_::to_ptr(hello) , boost_foreach_argument_dependent_lookup_hack_value)))))) {} else if (
boost::foreach_detail_::auto_any_t _foreach_cur9 = 
boost::foreach_detail_::begin(_foreach_col9 , (true ? 0 : 
boost::foreach_detail_::encode_type(hello, 
boost::foreach_detail_::is_const_(hello))) , (true ? 0 : 
boost::foreach_detail_::or_( 
boost::foreach_detail_::and_( 
boost::foreach_detail_::not_(
boost::foreach_detail_::is_array_(hello)) , (true ? 0 : 
boost::foreach_detail_::is_rvalue_((true ? 
boost::foreach_detail_::make_probe(hello) : (hello)), 0))) , 
boost::foreach_detail_::and_( 
boost::foreach_detail_::not_(boost_foreach_is_noncopyable( 
boost::foreach_detail_::to_ptr(hello) , boost_foreach_argument_dependent_lookup_hack_value)) , boost_foreach_is_lightweight_proxy( 
boost::foreach_detail_::to_ptr(hello) , boost_foreach_argument_dependent_lookup_hack_value)))))) {} else if (
boost::foreach_detail_::auto_any_t _foreach_end9 = 
boost::foreach_detail_::end(_foreach_col9 , (true ? 0 : 
boost::foreach_detail_::encode_type(hello, 
boost::foreach_detail_::is_const_(hello))) , (true ? 0 : 
boost::foreach_detail_::or_( 
boost::foreach_detail_::and_( 
boost::foreach_detail_::not_(
boost::foreach_detail_::is_array_(hello)) , (true ? 0 : 
boost::foreach_detail_::is_rvalue_((true ? 
boost::foreach_detail_::make_probe(hello) : (hello)), 0))) , 
boost::foreach_detail_::and_( 
boost::foreach_detail_::not_(boost_foreach_is_noncopyable( 
boost::foreach_detail_::to_ptr(hello) , boost_foreach_argument_dependent_lookup_hack_value)) , boost_foreach_is_lightweight_proxy( 
boost::foreach_detail_::to_ptr(hello) , boost_foreach_argument_dependent_lookup_hack_value)))))) {} else for (bool _foreach_continue9 = true; _foreach_continue9 && ! 
boost::foreach_detail_::done(_foreach_cur9 , _foreach_end9 , (true ? 0 : 
boost::foreach_detail_::encode_type(hello, 
boost::foreach_detail_::is_const_(hello)))); _foreach_continue9 ? 
boost::foreach_detail_::next(_foreach_cur9 , (true ? 0 : 
boost::foreach_detail_::encode_type(hello, 
boost::foreach_detail_::is_const_(hello)))) : (void)0) if (
boost::foreach_detail_::set_false(_foreach_continue9)) {} else for (char ch = 
boost::foreach_detail_::deref(_foreach_cur9 , (true ? 0 : 
boost::foreach_detail_::encode_type(hello, 
boost::foreach_detail_::is_const_(hello)))); !_foreach_continue9; _foreach_continue9 = true) 
    { 
     std::cout << ch; 
    } 

    return 0; 
} 

반복 할 가능성이 많은 유형이 있습니다. 당신이 손 코드 루프, 당신은 알고 활용할 수있는 경우

for(auto const &a: something){ .. } 

또는

for(auto a=begin(something);a!=end(something);++i){ .. } 
+1

하지만 그 대부분은 컴파일러가 템플릿 –

+0

으로 무엇을 할 것인지를 결정한 후에 null 코드로 끝날 것입니다. 어쨌든 위의 내용은 무슨 일이 벌어지고 있는지 보여줍니다. –

+0

예, 나는 그것이 사소한 것과는 거리가 멀다는 것을 이해합니다. 내 질문은 왜 그렇게되어야 하는가? 오버 헤드없이 단순 할 수없는 이유는 무엇입니까? – balki

0

거의 아무것도 돌이를 가능한 한 C++ (11 개)이 모든 트릭이 더 이상 필요하지 않습니다와 반복자와 범위의 (그러나 반드시 컴파일러 또는 boost_foreach) 속성은 아닙니다. 아마 당신은 더 잘할 수 있습니다.

또한 컴파일 타임에 클래스의 특정 속성을 감지 할 수 있어야하며 컴파일러가 사용할 템플릿 메커니즘을 지원할 수없는 경우 런타임까지이 작업을 연기해야합니다. 이것은 명백히 손으로 코딩 한 결과 (사용자가 알기 쉬운 곳)만큼 효율적이지는 않습니다.

2

좋아하는 컴파일러에 질문하지 않으시겠습니까?간단한을 위해 제공

~/projects$ clang++ -O2 -c -I/usr/lib/Boost/1-39-0-1/include/ test.cpp -emit-llvm 
~/projects$ llvm-dis test.o -show-annotations 

: 우리는 LLVM IR 검색이 명령으로

#include <cstring> 
#include <cstdio> 

#include <boost/foreach.hpp> 

char const* HelloWorld = "Hello, world!\n"; 

void simplefor() { 
    for(char const* it = HelloWorld, *end = HelloWorld + strlen(HelloWorld); 
     it != end; 
     ++it) 
    { 
    printf("%c", *it); 
    } 
} 

void foreach() { 
    BOOST_FOREACH(char ch, HelloWorld) 
    { 
    printf("%c", ch); 
    } 
} 

:

define void @_Z9simpleforv() nounwind uwtable { 
    %1 = load i8** @HelloWorld, align 8, !tbaa !0 ; [#uses=3 type=i8*] 
    %2 = tail call i64 @strlen(i8* %1) nounwind readonly ; [#uses=2 type=i64] 
    %3 = getelementptr inbounds i8* %1, i64 %2  ; [#uses=1 type=i8*] 
    %4 = icmp eq i64 %2, 0       ; [#uses=1 type=i1] 
    br i1 %4, label %._crit_edge, label %.lr.ph 

.lr.ph:           ; preds = %.lr.ph, %0 
    %it.01 = phi i8* [ %7, %.lr.ph ], [ %1, %0 ] ; [#uses=2 type=i8*] 
    %5 = load i8* %it.01, align 1, !tbaa !1   ; [#uses=1 type=i8] 
    %6 = sext i8 %5 to i32       ; [#uses=1 type=i32] 
    %putchar = tail call i32 @putchar(i32 %6) nounwind ; [#uses=0 type=i32] 
    %7 = getelementptr inbounds i8* %it.01, i64 1 ; [#uses=2 type=i8*] 
    %8 = icmp eq i8* %7, %3       ; [#uses=1 type=i1] 
    br i1 %8, label %._crit_edge, label %.lr.ph 

._crit_edge:          ; preds = %.lr.ph, %0 
    ret void 
} 

우리가 (혼란을 피하기 위해) 간단한 테스트 케이스를 사용하자

BOOST_FOREACH :

; [#uses=0] 
define void @_Z7foreachv() nounwind uwtable { 
    %1 = load i8** @HelloWorld, align 8, !tbaa !0 ; [#uses=1 type=i8*] 
    br label %2 

; <label>:2          ; preds = %.preheader, %0 
    %.in = phi i8* [ %6, %.preheader ], [ %1, %0 ] ; [#uses=2 type=i8*] 
    %3 = load i8* %.in, align 1, !tbaa !1   ; [#uses=2 type=i8] 
    %4 = icmp eq i8 %3, 0       ; [#uses=1 type=i1] 
    br i1 %4, label %.critedge, label %.preheader 

.preheader:          ; preds = %2 
    %5 = sext i8 %3 to i32       ; [#uses=1 type=i32] 
    %putchar = tail call i32 @putchar(i32 %5) nounwind ; [#uses=0 type=i32] 
    %6 = getelementptr inbounds i8* %.in, i64 1  ; [#uses=1 type=i8*] 
    br label %2 

.critedge:          ; preds = %2 
    ret void 
} 

단순한 케이스에 대해서는 더 많은 지시 사항이 있지만 (2 개가 아닌 반복마다 하나씩) 더 많은 명령어가 있다고 말할 수 있습니다.하지만 성능을 고정시키는 것은 어려울 것입니다.

물론 ... 더 이상 중요하지 않습니다! 우박 C++ 11 : 당신이 (CONST) 참조를 사용하는 경우, 컴파일러는 어떤 변수가없는 별칭을 수행하는 것이 연구 만 열심히 시간을 가지고, 덜 생성

void bestfor() { 
    for(char const ch: HelloWorld) { 
    printf("%c", ch); 
    } 
} 
0

나는 주로 때문에 앨리어싱의 생각 최적의 코드.