>

내가 보았거나 사용한 많은 라이브러리에는 이식 가능한 고정 크기 변수, 예를 들어 int8, uint8, int16, uint16 등을 제공하기 위해 typedef가 있으며 플랫폼에 관계없이 올바른 크기가됩니다 (c ++ 11은 자체적으로 헤더 stdint.h)

최근에 작은 라이브러리에서 이진 파일 I/O를 사용한 후 필자가 작성하는 방식으로 typedef를 사용하는 이점을 볼 수 있습니다.

그러나 기본 유형을 사용하지 않고 "namespace :: uint32"를 입력하는 데 어려움을 겪을 경우 가능한 한 대체를 유용하게 만들 수 있습니다. 따라서 간단한 typedef 대신 클래스 사용을 고려하고 있습니다.

이 래퍼 클래스는 모든 일반 연산자를 구현하므로 기본 유형과 상호 교환 가능하게 사용할 수 있습니다.

예 :

int x = 0;
//do stuff

가 될 수있다

class intWrapper {
//whatever
};
intWrapper = 0;
//do stuff

"// do stuff"에서 코드를 수정하지 않고도

typedef와 달리이 접근법을 고려하는 이유는 기본 유형에서 작동하는 함수가 이미 존재하기 때문입니다.

std::string numberToString(double toConvert);
std::string numberToHexString(double toConvert);
int intToXSignificantPlaces(const int& number, 
                               unsigned char numberOfSignificantPlaces);
bool numbersAreApproximatelyEqual(float tollerance);
//etc....

구문 적으로 다음을 수행하는 것이 더 좋을 것입니다.

intWrapper.toString();
intWrapper.toHexString();
//etc

또한 bigint 클래스 (int128 등)를 구현하고 기본 클래스를 기반으로하는 작은 클래스와 동일한 클래스를 사용하도록합니다.

마지막으로 각 래퍼에는 max 및 min이라는 정적 인스턴스가있을 수 있으므로 int32 :: max 및 int32 :: min의 멋진 구문이 가능합니다.

그러나이 작업을 수행하기 전에 해결해야 할 몇 가지 우려 사항이 있습니다 (대부분은 구문 설탕이므로 이러한 유형은 일반적으로 사용되므로 추가 오버 헤드는 성능에 상당한 영향을 줄 수 있습니다).

1) int a + int b를 통해 someClass.operator + (), someClass.operator- () 등을 사용할 때 오버 헤드를 호출하는 추가 함수가 있습니까? 그렇다면 연산자 + ()를 인라인하면이 모든 오버 헤드가 제거됩니까?

2) 모든 외부 함수에는 기본 유형이 필요합니다. 예 : glVertex3f (float, float, float)는 단순히 3 개의 floatWrapper 객체를 전달할 수 없었습니다. 컴파일러가 floatWrapper를 float로 자동 캐스팅하는 방법이 있습니까? 그렇다면 성능에 영향이 있습니까?

3) 추가 메모리 오버 헤드가 있습니까? 상속이있는 클래스에는 일종의 가상 테이블 포인터가 있으므로 약간 더 많은 메모리를 사용하거나 가상 함수에만 사용한다는 것을 이해하지만이 래퍼 클래스가 상속되지 않거나 자식 클래스가 아니라고 가정하면 기본 유형 대신 클래스를 사용하는 추가 메모리 사용이 있습니까?

4) 이로 인해 발생할 수있는 다른 문제/성능에 영향이 있습니까?

  • 답변 # 1

    와이즈 비즈

    아니요, 함수 본문이 작고 헤더에 있으면 인라인되어 오버 헤드가 없습니다

    와이즈 비즈

    1) Is there any additional function calling overhead when using someClass.operator+()

    함수의 본문이 작고 머리글에 있으면 인라인되어 오버 헤드가 없습니다

    와이즈 비즈

    가상 기능이 없다면 아닙니다. 클래스가 가상 함수를 선언하거나 상속하면다형성이라고합니다. 클래스가 다형성이 아닌 경우 객체는 가상 함수 테이블에 대한 포인터를 포함 할 필요가 없습니다. 또한 비다 형성 클래스에 대한 포인터/참조의 상속 계층에서 파생 클래스에 대한 포인터/참조에 대한 상속 계층 구조를 수행하는 것은 허용되지 않으므로 객체에 일종의 유형 정보가있을 필요는 없습니다.

    와이즈 비즈

    성능? 아니요.

    또한 lhs를 자유 함수로 수정하지 않는 이진 연산자를 구현하고

    2) Is there a way to automatically make the compiler cast the floatWrapper to a float?

    의 모든 관련 순열을 지원하도록 오버로드하십시오.  그리고 struct floatWrapper { floatWrapper(float); //implicit conversion from float operator float(); //implicit conversion to float. }; .

    3) Is there any additional memory overhead?

    여기에 이런 시도가 있습니다. float/double/long double에는 약간 다른 버전이 필요합니다.

  • 답변 # 2

    컴파일러에 따라 다릅니다. 루프 나 할당이 있으면 인라인 될 가능성이 줄어 듭니다.

  • 답변 # 3

    답이 완전히 정확하지 않다고 생각합니다. 적어도 gcc 4의 경우 생성자와 연산자 호출로 인해 상당한 오버 헤드가 발생했습니다.

    다음은

    4) Are there any other problems / performance impacts this could cause?

    보다 약 2 배가 걸립니다. :

    floatWrapper
    
    

    최적화 여부에 관계없이 다른 버전의 gcc 4를 사용하면 성능에 차이가 없었습니다.

    이 경우 추가

    float
    
    

    약간 개선 된 부분 만 제공합니다.

    성능이 중요한 코드에서 기본 유형 인 것처럼 래퍼를 사용하는 것은 나쁜 생각 인 것 같습니다. 로컬에서 사용하여 생성자를 항상 호출하는 것이 훨씬 더 나빠 보입니다.

    이것은 정말 놀랍습니다. 모든 것을 인라인하고 기본 유형 변수처럼 최적화 할 수 있어야하기 때문입니다.

    추가 힌트가 있으면 대단히 감사하겠습니다!

    struct floatWrapper { explicit floatWrapper(float); operator float(); //implicit conversion to float. floatWrapper operator-=(float); }; floatWrapper operator-(floatWrapper lhs, floatWrapper rhs) {return lhs-=rhs;} floatWrapper operator-(float lhs, floatWrapper rhs) {return floatWrapper(lhs)-=rhs;} floatWrapper operator-(floatWrapper lhs, float rhs) {return lhs-=rhs;}

  • 이전 f# - 꼬리 재귀 목록 추가를 어떻게 구현할 수 있습니까?
  • 다음 구문 중 루비