2011-02-24 2 views
1

저는 Java와 C 모두에서 프로그램을 작성했습니다. 이제는 C++로 손을 더럽 히고 있습니다.회원 기능에 반복적 인 전화가 상처를 입니까?

class Booth { 

private : 
      int tickets_sold; 
public : 
      int get_tickets_sold(); 
      void set_tickets_sold(); 
}; 
자바에서

, 내가 tickets_sold의 값을 필요한 곳에, 나는 반복적으로 게터를 부를 것이다 :

이 코드를 감안할 때. CI에서

if (obj.get_tickets_sold() > 50 && obj.get_tickets_sold() < 75){ 
    //do something 
} 

단지 구조에서 특정 변수의 값을 얻을 것입니다 : 예를 들어

C에서 구조를 사용하는 동안

if(obj_t->tickets_sold > 50 && obj_t->tickets_sold < 75){ 
    //do something 
} 

그래서, 나는 두 통화에서 저장을 그 나는 그렇지 않으면 Java에서 두 게터를 만들 것입니다. 실제 호출이나 Java가 어떻게 든 호출하는 지 확실하지 않습니다.

요점은 내가 Java에서 C++로 사용한 것과 동일한 기술을 사용하면 getter 멤버 함수에 대한 두 번의 호출이 비용이 들거나 컴파일러가 어떻게 든 코드를 인라인한다고 알고 있습니까? 나는 자바에서이 걱정 것,

int num_tickets = 0; 

if ((num_tickets = obj.get_ticket_sold()) > 50 && num_tickets < 75){ 
    //do something 
} 

내가 꽉 코드를 작성하고 불필요한 함수 호출을 피하려는 (? 따라서 모두 함수 호출의 오버 헤드를 줄일 수)

는 다른 방법으로, 내가 더 잘 사용하고 있습니다 왜냐하면, 우리 모두 왜 그 이유를 알고 있기 때문입니다. 그러나 내 코드를 읽을 수 있고 수행 할 내용을 정확하게 반영하기 위해 privatepublic 키워드를 사용하고 싶습니다.

+0

성능에 대해 걱정하시는 이유는 무엇입니까? – GManNickG

+0

왜냐하면 내가 임무를 수행해야하고 가장 빠른 실행 코드가 보너스 포인트를 얻을 수도 있기 때문입니다. –

+3

좋은 디자인 대신 성과가 중요하다고 생각하게 만들기 위해 선생님 께 수치스러워합니다. – GManNickG

답변

5

언어를 배우는 사람이라면 걱정할 필요가 없습니다. 그렇지 않으면 입증 될 때까지 충분히 빨리 고려하십시오. 즉, 오해의 소지가 있거나 불완전한 대답이 많으므로 기록을 위해 약간의 미묘한 함의를 살필 것입니다. 클래스를 고려

class Booth 
{ 
    public: 
    int get_tickets_sold(); 
    void set_tickets_sold(); 
    private: 
    int tickets_sold; 
}; 

은 얻을 설정 기능 (A 정의라고도 함) 구현은 아직

를 지정되지 않았습니다. 클래스 선언 안에 함수 본문을 지정한 경우 컴파일러는 암시 적으로 해당 함수가 본문에 삽입되도록 요청한 것으로 간주합니다 (지나치게 큰 경우에는 무시할 수 있음). 나중에 inline 키워드를 사용하여 지정하면 정확하게 안전한 결과를 얻습니다. 약식 ...

class Booth 
{ 
    public: 
    int get_tickets_sold() { return tickets_sold; } 
    ... 

... 그리고 ...

class Booth 
{ 
    public: 
    int get_tickets_sold(); 
    ... 
}; 

inline int Booth::get_tickets_sold() { return tickets_sold; } 

... 적어도 표준이 기대하는 우리를 격려 어떤 측면에서 (동일하지만, 각 컴파일러 휴리스틱는 다를 수 있습니다 - 인라이닝은 컴파일러가 무시할 수있는 요청입니다.

inline 키워드없이 나중에 함수 본문을 지정하면 컴파일러는 해당 함수 본문을 인라인 할 의무가 없지만 여전히 선택할 수 있습니다.동일한 번역 단위 (즉, 컴파일중인 .cc/.cpp/.C++/etc. "구현"파일 또는 직접 또는 간접적으로 포함 된 일부 헤더)에 표시 될 가능성이 훨씬 큽니다. 구현이 링크 시간에만 사용 가능한 경우 함수는 모두에 인라인되지 않을 수 있지만 특정 컴파일러와 링커가 상호 작용하고 협조하는 방식에 따라 다릅니다. 이 아닌은 단순히 최적화를 실현하고 마법을 기대할 수있는 문제입니다.

// inline.h: 
void f(); 

// inline.cc: 
#include <cstdio> 
void f() { printf("f()\n"); } 

// inline_app.cc: 
#include "inline.h" 
int main() { f(); } 

이 건물 :

g++ -O4 -c inline.cc 
g++ -O4 -o inline_app inline_app.cc inline.o 

를 인라인 조사 : 실행이에 0x08048416에) (주에서 0x080483f3에서 갔다

$ gdb inline_app 
... 
(gdb) break main 
Breakpoint 1 at 0x80483f3 
(gdb) break f 
Breakpoint 2 at 0x8048416 
(gdb) run 
Starting program: /home/delroton/dev/inline_app 

Breakpoint 1, 0x080483f3 in main() 
(gdb) next 
Single stepping until exit from function main, 
which has no line number information. 

Breakpoint 2, 0x08048416 in f() 
(gdb) step 
Single stepping until exit from function _Z1fv, 
which has no line number information. 
f() 
0x080483fb in main() 
(gdb) 

공지 사항을 이것을 증명하려면 다음 코드를 고려 f()를 누른 다음 main()의 0x080483fb로 돌아가십시오 ... 명확하게 이 아닌 인라인됩니다. 이것은 함수의 구현이 간단하기 때문에 인라이닝을 기대할 수 없다는 것을 보여줍니다.

이 예제는 개체 파일의 정적 링크와 관련이 있습니다. 분명히 라이브러리 파일을 사용하는 경우 은 실제로 함수를 인라이닝하지 않으므로 클라이언트 코드를 다시 컴파일하지 않고도 라이브러리를 업데이트 할 수 있습니다. 링크가 어쨌든 로딩 타임에 암묵적으로 수행되는 공유 라이브러리의 경우 더욱 유용합니다.

자주 사용되는 클래스는 성능에 중요한 루프 내에서 호출 될 것으로 예상되는 경우 예상되는 인라인 함수 정의 (예 : 내부 클래스 또는 inline 키워드)의 두 가지 형식을 사용하지만 반대 고려 사항 함수를 인라이닝 (inlining)하여 함수에 대한 변경 사항을 가져 오기 위해 클라이언트 코드를 재 컴파일 (상대적으로 느리거나 자동화 된 트리거가 없을 수도 있음)하고 relinked (빠른 실행, 다음 실행시 빠른 실행) 이행.

이런 종류의 고려 사항은 성가시다. 그러나 이러한 절충안을 계획적으로 관리하면 수십 억 가지 라인과 수천 개의 개별 프로젝트로 확장하여 수십 년 동안 다양한 라이브러리를 공유 할 수 있습니다.

다른 작은 세부 사항 : 야구장 그림과 같이 라인 밖 가져 오기/설정 기능은 일반적으로 인라인 코드보다 약 10 배 느립니다. CPU, 컴파일러, 최적화 수준, 변수 유형, 캐시 히트/미스 등으로 분명히 달라질 것입니다.

+0

고맙습니다 .. !!! 그것은 통찰력이 있었고 youve는 지금 나에게 분명히 그것을 분명하게 만들었다 ..! –

+0

@ Rahul : 대단히 환영합니다. C++을 즐기시 길 바랍니다. 훌륭한 언어입니다. 건배. –

4

멤버 함수를 반복적으로 호출해도 문제가 발생하지 않습니다.

getter 함수 인 경우 C++ 컴파일러 (적어도 릴리스/최적화 된 빌드)에서는 인라인됩니다. Java Virtual Machine은 특정 함수가 자주 호출되고 최적화된다는 것을 "알 수 있습니다" 그에 대한. 따라서 일반적으로 함수를 사용하면 성능상의 불이익은 거의 발생하지 않습니다.

항상 가독성을 우선으로 작성해야합니다. 물론 that's not to say that you should completely ignore performance outright이지만 성능이 좋지 않으면 코드를 프로파일 링하여 가장 느린 부분이 어디에 있는지 확인할 수 있습니다.

또한 getter 함수 뒤에있는 변수 tickets_sold에 대한 액세스를 제한함으로써 의 멤버 함수에 대한 tickets_sold 변수를 수정할 수있는 코드 만 보장 할 수 있습니다. 이렇게하면 프로그램 동작에서 불변량을 적용 할 수 있습니다.

예를 들어, tickets_sold은 분명히 음수 값이되지는 않습니다. 그것은 구조의 불변량입니다. tickets_sold을 비공개로 만들고 해당 멤버 함수가 해당 불변 조건을 위반하지 않도록함으로써 불변 식을 적용 할 수 있습니다. Booth 클래스는 다른 모든 사용자에게 게터 함수를 통해 tickets_sold을 "읽기 전용 데이터 멤버"로 사용할 수있게하고 여전히 불변성을 보존합니다.

공용 변수를 만드는 것은 누구나 tickets_sold에있는 데이터를 뒤적 거리며 이동할 수 있다는 것을 의미합니다. 이는 기본적으로 tickets_sold에 모든 불변량을 적용하는 능력을 완전히 파괴합니다. 어떤 사람이 tickets_sold에 음수를 쓰는 것은 가능합니다. 물론 무의미합니다.

1

컴파일러는 이와 같이 함수 호출을 인라인 할 가능성이 큽니다.

8

프로그램이 너무 느린 경우를 제외하고는 별 문제가되지 않습니다. 99.9999 %의 코드에서 함수 호출의 오버 헤드는 중요하지 않습니다. 가장 명확하고, 유지 보수가 쉽고, 이해하기 쉬운 코드를 작성하고, 성능상의 문제가있는 곳을 알고 난 후에 만 ​​성능 조정을 시작하십시오.

즉, 현대 C++ 컴파일러 (일부 링커)는 함수, 특히이 함수와 같은 간단한 함수를 인라인 할 수 있고 인라인 할 수 있습니다.

+1

+1 그들은뿐만 아니라 그들도 할 수있을뿐만 아니라 자신의 재량에 따라, 'inline' 태그를 넣으십시오! 그것은 그것을 단지 제안으로 본다. – corsiKa

1
class Booth { 
public: 
    int get_tickets_sold() const { return tickets_sold; } 

private: 
    int tickets_sold; 
}; 

귀하의 컴파일러 해야 인라인 get_tickets_sold, 나는 그것을하지 않았다 경우 매우 놀랄 것입니다. 그렇지 않으면 새 컴파일러를 사용하거나 최적화를 사용해야합니다.

0

소금을 쓸만한 컴파일러는 getter를 직접 멤버 액세스에 최적화 할 수 있습니다. 최적화가 명시 적으로 비활성화 된 경우 (예 : 디버그 빌드의 경우) 또는 두뇌가 발생하지 않는 컴파일러를 사용하는 경우 (이 경우 실제 컴파일러에서 심각하게 고려해야합니다)에만 발생합니다.

0

컴파일러는 작업을 수행 할 가능성이 높지만 일반적으로 멤버에 대한 액세스를 const 참조로 만들지 않는 한 Java 관점보다는 C 관점에서 접근합니다. 그러나, 정수를 다루는 경우, 복사 (적어도 32 비트 환경은 둘 다 4 바이트이기 때문에)를 통해 const 참조를 사용하는 것이 일반적으로 가치가 없으므로 예제는 실제로 여기 좋은 것이 아닙니다. 아마 이것은 당신은 C++의 게터/세터를 사용하는 이유 설명 :

다음 여분의 로직을 수행 할 수 있도록 할 것 세터를 통해 제외하고 수정을 방지
class StringHolder 
{ 
public: 
    const std::string& get_string() { return my_string; } 
    void set_string(const std::string& val) { if(!val.empty()) { my_string = val; } } 
private 
    std::string my_string; 
} 

. 그러나 이와 같은 간단한 클래스에서이 모델의 가치는 0이 아니며, 더 많은 타입을 추가하고 실제로 가치를 추가하지 않은 코더를 만들었습니다. 그런 클래스의 경우 getter/setter 모델을 사용할 수 없습니다.