C++에서는 클래스를 통해 객체를 생성하려면 생성자를 거쳐야 하고 소멸시키려면 소멸자를 거쳐야 합니다.
(소멸자는 생성의 역순으로 호출됩니다.)
기본 생성자
– 매개변수가 없는 생성자
– 클래스 선언 시 생성자를 선언하지 않으면 기본 생성자가 자동으로 정의된다.
– 생성자를 하나만 선언해도 컴파일러는 암시적으로 기본 생성자를 정의하지 않습니다.
암시적 기본 생성자
컴파일러에 의해 자동으로 생성되는 생성자
class Test{
public:
// Test(){} // 묵시적 디폴트 생성자
void foo(){}
};
int main(){
Test test;
}
class Test{
private:
int value{0};
public:
// 묵시적 디폴트 생성자가 생성되지 않는다!
Test(int value):value{value}{ // 생성자 초기화 리스트
}
void foo(){}
};
* 생성자 초기화 목록
1. 생성자에서만 사용할 수 있습니다.
2. 객체 생성 후 값을 할당하는 대신 객체 생성과 동시에 값을 할당할 수 있습니다.
3. const 변수도 값으로 초기화할 수 있습니다.
class Test{
private:
const int value{0};
public:
Test(int value):value{value}{ // 상수 변수도 초기화 가능
// value = 5; // 불가능!
}
void foo(){}
};
복사 생성자
같은 클래스의 객체를 복사하여 객체를 생성하는 생성자
명시적 복사 생성자
매개변수는 const 참조 유형이어야 합니다. (원본을 변경하지 않는 const)
class Test{
...
public:
Test(const Test& other){}
}
암시적 복사 생성자
복사 생성자를 선언하지 않으면 컴파일러가 복사 생성자를 생성합니다.
class Test(){
int value;
public:
Test(int value):value{value}{}
// Test(const Test& other){} // 묵시적 복사 생성자
};
int main(){
Test t1(10);
Test t2 = t1; // 대입 연산자가 오버로딩 되어있지 않으므로, 복사 생성자가 호출된다!
}
암시적 복사 생성자의 문제
원래 얕은 복사만 수행
얕은 복사는 값을 복사하지 않고 주소만 복사하는 것을 의미합니다.

객체에 주소값을 저장하는 변수가 있다면,
의도하지 않는 한 깊은 복사필수적이다!
(따라서 사용자는 명시적으로 복사 생성자를 생성해야 합니다.)
이동 생성자
이동 생성자의 호출 조건
1. 임시 객체를 전달할 때
2. 표준::이동()다음을 사용하여 인수를 r-값 참조라고 하는 것으로 변환하여 전달할 때
r-value 참조로 전달된 동일한 객체의 내용을 이동하여 객체를 생성하는 생성자
복사 생성자가 효과적이긴 하지만 때때로 반복해서 복사하면 메모리에 계속 복사되어 효율성이 떨어집니다.
임시 개체를 만들면 어쨌든 사라집니다. 깊은 복사불필요하게 리소스를 소모하게 됩니다. 따라서 임시 개체를 만들 때 이동 생성자를 사용하여 프로그램 부하를 최소화합니다.
이동 생성자가 호출될 때 얕은 복사하고 원본의 소유권을 양도합니다.
class Test{
private:
int* arr;
public:
Test(int value):arr{new int(value)}{}
~Test(){
std::cout << &arr << std::endl;
}
Test(Test&& other){
// do something
}
};
int main(){
Test t1;
Test t2(std::move(t1));
}
위의 경우 t1의 소유권이 t2에게 이전됩니다. 이동하다있는 상태이다
메인 함수가 종료되면 t1의 소멸자가 정상적으로 호출되지만 내부 내용은 비어 있고 t1의 원래 내용은 t2로 이동되었습니다.
따라서 t1의 소멸자가 호출되면 arr의 값이 가비지(또는 nullptr)로 출력된다.
t2의 소멸자가 호출되면 원래 t1 arr 주소의 arr 값이 출력됩니다.
복사 제거
int main() {
Test t1(1);
Test t1_copy(t1);
Test t2(Test(6)); // how?
}
성공적으로 컴파일되면
테스트() t1
테스트(const 테스트&) t1_copy
테스트() t2
~테스트() t2
~테스트() t1_copy
~테스트() t1
로 출력된다
기본 생성자는 t1이 생성될 때 한 번 호출되며,
t1_copy가 생성되면 t1의 복사 생성자가 호출됩니다.
이것은 우리가 아는 한입니다.
t2도 알려져 있음을 고려하면,
Test(6) 개체를 만들기 위해 기본 생성자가 호출됩니다.
t2는 해당 임시 객체로 복사 생성되므로 복사 생성자를 호출해야 합니다.
그러나 출력에서 복사 생성자는 호출되지 않습니다!
Test t2(Test(6));
Test t2(6);
위의 두 코드는 동일한 기능을 수행하므로 Test(6)에서 임시 개체의 복사본을 만들 필요가 없습니다.
따라서 스마트 컴파일러는 Test(6) t2에서 생성된 임시 개체를 만듭니다.
이거 야 복사 생략오전.