반응형
안녕하세요, 오늘은 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가 널포인터를 반환했다는 것이고,
그말은 형변환 실패란 뜻입니다.
반응형
'C++ > C++ 특수 강좌 & 모던 C++' 카테고리의 다른 글
C++20 Concepts 알아보기 (1) (0) | 2022.02.16 |
---|---|
[C++20 특수 강좌] 선택문 최적화를 위한 [[likely]], [[unlikely]] (0) | 2022.02.16 |
[C++20 특수 강좌] constexpr을 넘어선 consteval (0) | 2022.02.16 |
[C++심화 강좌] C++20 모듈 사용하기 (0) | 2021.05.15 |