C++/C++ 특수 강좌 & 모던 C++

C++ 캐스팅 연산자 성능 비교

카루-R 2022. 2. 16. 13:26
반응형

안녕하세요, 오늘은 C++의 형변환(캐스팅) 연산자의 성능을 알아보겠습니다.

 

static_cast

dynamic_cast

reinterpret_cast

(type)obj // C-style cast

type(obj) // functional cast(변환 생성자 이용)

 

CA클래스를 상속받는 CB클래스를 만들고, who_am_I 메서드를 만들어서 제대로 되었는지 확인해 보겠습니다.

 

각각 1억번씩 형 변환 테스트를 해보겠습니다.

 코드는 위가 싱글스레드, 밑에가 멀티스레드 입니다.

#include <algorithm>
#include <array>
#include <iostream>
#include <ctime>
using namespace std;
 
class CA {
public:
    CA() = default;
    virtual void who_am_I() const {        
        cout << "CA" << endl;
    }
};
 
class CB : public CA {
public:
    CB() = default;
    explicit CB(const CA &A) {}
    virtual void who_am_I() const {
        cout << "CB" << endl;
    }
};
 
int main() {
    CA A, *pA{ nullptr };
    CB B, *pB{ nullptr };
 
    pA = &B;   // pB = &A;        // 에러!!
    array<clock_t, 20> arr{ 0L };
    array<clock_t, 5> cast_result{ 0L, 0L, 0L, 0L, 0L };
    clock_t start{ 0L }, end{ 0L };
 
    cout << "*********** STATIC_CAST *************" << endl << endl;
    for (auto &cl : arr) {           
        start = clock();
 
        for (int i = 0; i < 100'000'000; i++)
                pB = static_cast<CB *>(&A);
 
        end = clock(); 
        cl = end - start;        
    }        
 
    pB->who_am_I();
    for_each(arr.begin(), arr.end(), [&](clock_t n) { cast_result.at(0) += n; });   
 
    cout << "********** DYNAMIC_CAST ***********" << endl << endl;
    for (auto &cl : arr) {            
        start = clock();
 
        for (int i = 0; i < 100'000'000; i++)
            pB = dynamic_cast<CB *>(&A);
 
        end = clock();           
        cl = end - start;        
    }        
 
    if (pB != nullptr)
        pB->who_am_I();

    for_each(arr.begin(), arr.end(), [&](clock_t n) { cast_result.at(1) += n; });
 
    cout << "*********** C_STYLE_CAST ************" << endl << endl;
    for (auto &cl : arr) {
        start = clock();
 
        for (int i = 0; i < 100'000'000; i++)        
            pB = (CB*)(&A);
 
         end = clock();       
        cl = end - start;
    }       
 
    pB->who_am_I();
    for_each(arr.begin(), arr.end(), [&](clock_t n) { cast_result.at(2) += n; });
 
    cout << "********* FUNCTIONAL CAST *********" << endl << endl;
    for (auto &cl : arr) {       
        start = clock();
 
        for (int i = 0; i < 100'000'000; i++)    
            pB = &CB(A);
 
        end = clock();     
        cl = end - start;       
    }       
    pB->who_am_I();
    for_each(arr.begin(), arr.end(), [&](clock_t n) { cast_result.at(3) += n; }); 
 
     cout << "********* REINTERPRET_CAST *********" << endl << endl;
     for (auto &cl : arr) {     
         start = clock();
         for (int i = 0; i < 100'000'000; i++)     
            pB = reinterpret_cast<CB *>(&A);   
         end = clock();                cl = end[4] - start[4];       
    } 
    pB->who_am_I();
    for_each(arr[4].begin(), arr[4].end(), [&](clock_t n) { cast_result.at(4) += n; });
 
    const char* msg[5] {   
        "static_cast : ",
        "dynamic_cast : ",
        "C-style cast : ",
        "functional cast : ",
        "reinterpret_cast : ",
    };
   
    for (int i{0}; auto &r : cast_result) {
        cout << endl << msg[i] << r << endl;
        ++i;    
    }    
 
    return 0;
}
import std.core;
import std.threading;
#include "ctime"

using namespace std;

class CA {
public:
    CA() = default;
    virtual void who_am_I() const {
        cout << "CA" << endl;
    }
};

class CB : public CA {
public:
    CB() = default;
    explicit CB(const CA &A) {}
    virtual void who_am_I() const {
        cout << "CB" << endl;
    }
};

int main() {
    CA A, *pA{ nullptr };
    CB B, *pB{ nullptr };

    pA = &B;   // pB = &A;           // 에러!!

    array<array<clock_t, 5>, 20> arr{ 0L };
    array<clock_t, 5> cast_result{ 0L, 0L, 0L, 0L, 0L };
    array<clock_t, 5> start{ 0L }, end{ 0L };

    thread t1([&] {
        for (cout << "*********** STATIC_CAST *************\n\n"; auto &cl : arr[0]) {
            start[0] = clock();

            for (int i = 0; i < 100'000'000; i++)
                pB = static_cast<CB *>(&A);

            end[0] = clock();
            putc('-', stdout);
            cl = end[0] - start[0];
        }
        putc('\n', stdout);
        pB->who_am_I();
        for_each(arr[0].begin(), arr[0].end(), [&](clock_t n) { cast_result.at(0) += n; });
    });

    thread t2([&] {
        for (cout << "********** DYNAMIC_CAST ***********\n\n"; auto &cl : arr[1]) {
            start[1] = clock();

            for (int i = 0; i < 100'000'000; i++)
                pB = dynamic_cast<CB *>(&A);

            end[1] = clock();
            putc('*', stdout);
            cl = end[1] - start[1];
        }
        putc('\n', stdout);

        if (pB != nullptr)
            pB->who_am_I();

        for_each(arr[1].begin(), arr[1].end(), [&](clock_t n) { cast_result.at(1) += n; });
    });

    thread t3([&] {
        for (cout << "*********** C_STYLE_CAST ************\n\n"; auto &cl : arr[2]) {
            start[2] = clock();

            for (int i = 0; i < 100'000'000; i++)
                pB = (CB*)(&A);

            end[2] = clock();
            putc('=', stdout);

            cl = end[2] - start[2];
        }
        putc('\n', stdout);
        pB->who_am_I();

        for_each(arr[2].begin(), arr[2].end(), [&](clock_t n) { cast_result.at(2) += n; });
    });

    thread t4([&] {
        for (cout << "********* FUNCTIONAL CAST *********\n\n"; auto &cl : arr[3]) {
            start[3] = clock();

            for (int i = 0; i < 100'000'000; i++)
                pB = &CB(A);

            end[3] = clock();
            putc('_', stdout);
            cl = end[3] - start[3];
        }
        putc('\n', stdout);
        pB->who_am_I();

        for_each(arr[3].begin(), arr[3].end(), [&](clock_t n) { cast_result.at(3) += n; });
    });

    thread t5([&] {
        for (cout << "********* REINTERPRET_CAST *********\n\n"; auto &cl : arr[4]) {
            start[4] = clock();

            for (int i = 0; i < 100'000'000; i++)
                pB = reinterpret_cast<CB *>(&A);

            end[4] = clock();
            putc('~', stdout);
            cl = end[4] - start[4];
        }
        putc('\n', stdout);
        pB->who_am_I();

        for_each(arr[4].begin(), arr[4].end(), [&](clock_t n) { cast_result.at(4) += n; });
    });

    const char* msg[5] {
        "static_cast : ",
        "dynamic_cast : ",
        "C-style cast : ",
        "functional cast : ",
        "reinterpret_cast : ",
    };

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();

    for (int i{0};auto &r : cast_result) {
        cout << endl << msg[i] << r << endl;
        ++i;
    }
    return 0;
}

두번째 소스에서 

'import std.core;'

 구문을 보셨나요?

 

예... 드디어 C++에도 모듈이 등장하려나 봅니다. 비주얼 스튜디오 2017.3에서 작동합니다.

 

결과부터 알려드리겠습니다.

 

<소스코드 1>

static_cast : 0.16395초

dynamic_cast : 2.00015초

C-style cast : 0.1577초 (어? 1577?)

functional cast : 3.4268초

reinterpret_cast : 0.15905초

 

의외로 변환생성자를 통한 형변환이 가장 시간이 오래걸리네요? 

함수 호출때문에 그런가 봅니다...;;

dynamic_cast는 예상 했고...

 

역시 static_cast는 빠른 편이군요.

 
<소스코드 2>
-중간에 멈춤-
 
너무 많은 스레드를 생성했나...?
 
그렇다고 static_cast만 쓰라는 건 아닙니다.
dynamic_cast로 형변환시, 아무것도 출력되지 않는 것을 볼 수 있습니다.
아무것도 없는데 뭘 봐
 
그것은 dynamic_cast가 널포인터를 반환했다는 것이고,
그말은 형변환 실패란 뜻입니다.
반응형