#include <type_traits>
struct TrivialDefaultCtor // true
{
int data;
};
struct NonTrivialDefaultCtor // false
{
int data;
NonTrivialDefaultCtor() {} // 사용자가 만든 디폴트 생성자
};
struct Type1 // false
{
// 컴파일러가 디폴트 생성자 제공안함
Type1(int a) {}
};
struct Type2 // false
{
Type2() {};
Type2(int a) {}
};
struct Type3 // true
{
Type3() = default;
Type3(int a) {}
};
struct Type4 // false
{
int data = 0;
// int data;
// Type4() : data(0) {}
};
struct Type5 // false
{
int data;
virtual void foo() {} // 가상 함수 테이블 초기화
};
struct Type6 // false
{
int data1;
NonTrivialDefaultCtor data2;
// Type6() : data2() {} // 컴파일러가 추가한 코드
};
struct Type7 // true
{
int data1;
TrivialDefaultCtor data2;
// Type7() : data2() {} // 생성자가 하는 일 없음
};
struct Type8 : public NonTrivialDefaultCtor // false
{
int data;
// 기반 클래스의 생성자를 호출
};
struct Type9 : public TrivialDefaultCtor // true
{
int data;
};
struct Type10 : public virtual TrivialDefaultCtor // false
{
// 가상 상속을 받으면 디폴트 생성자에서 가상 상속을 위한 초기화 필요
};
struct Type11 // false
{
Type11() = delete; // 디폴트 생성자가 없음
};
struct Type12 // false
{
int& ref; // 참조 멤버가 있으면 디폴트 생성자는 delete됨
};
struct Type13 // false
{
const int c; // 상수 멤버가 있어도 디폴트 생성자는 delete됨
};
template<class T> void check()
{
std::cout << typeid(T).name() << " : ";
std::cout << std::boolalpha;
std::cout << std::is_trivially_default_constructible_v<T> << std::endl;
};
디폴트 생성자가 Trivial하다면 생성자를 부를 필요가 없음
(어셈블리 단계에서도 디폴트 생성자를 호출하지 않음)
컴파일러가 생성한 복사 생성자가
사용자가 직접 객체를 memmove 등으로 복사하는 것과 동일할 때
- 복사 생성자를 사용자가 만들지 않고
- 가상 함수가 없고
- 가상 상속을 하지 않고
- 기반 클래스가 없거나 기반 클래스의 복사 생성자가 Trivial하고
- 멤버 데이터의 복사 생성자가 Trivial 함
#include <type_traits>
class Point
{
int x;
int y;
// std::string s; // 동적 메모리 할당을 위해 복사 생성자를 만듦, Trivial하지 않음
public:
Point() = default;
Point(int a, int b) : x(a), y(b) {}
// virtual void foo(){} // 가상 함수 테이블, Trivial하지 않음
};
int main()
{
std::cout << std::is_trivially_copy_constructible_v<Point> << std::endl;
Point pt1(1,2);
Point pt2 = pt1;
Point pt3;
memmove(&pt3, &pt1, sizeof(Point));
}
컴파일러가 생성한 복사 생성자로 모든 멤버를 복사하는 것 외에는 아무 일도 하지 않음
#include <type_traits>
struct Point
{
int x = 0;
int y = 0;
};
template<class T>
void copy_type(T* dst, T* src, std::size_t sz)
{
if constexpr ( std::is_trivially_copy_constructible_v<T> )
{
std::cout << "using memcpy" << std::endl; // 메모리 복사
memcpy(dst, src, sizeof(T)*sz);
}
else
{
std::cout << "using copy ctor" << std::endl; // 복사 생성자
while(sz--)
{
new(dst) T(*src); // placement new
++dst, ++src;
}
}
}
int main()
{
Point arr1[5];
Point* arr2 = static_cast<Point*>( operator new(sizeof(Point) * 5) );
copy_type(arr1, arr2, 5);
// 메모리 해제
}