헤더파일

템플릿 - 3 본문

C++

템플릿 - 3

헤더파일 2018. 3. 22. 11:54

min 함수는 템플릿 함수이다.

min(1,3) 을 쓰면 디폴트로 작은 정수를 뽑아내서 1을 내보낸다.

하지만 min(1,3, [](){ }) 람다로 다른 기준을 줄수도 있다.


class Dog

{

public:

Dog(int age) :m_age(age) {}

int m_age = 0;

};


cout << min<Dog>(Dog(1), Dog(3), 

[](const Dog& a, const Dog& b) {return a.m_age < b.m_age; }).m_age<< endl;



class Dog

{

public:

Dog(int age) :m_age(age) {}

int m_age = 0;

bool operator>(const Dog& other)

{

return m_age > other.m_age;

}

friend ostream& operator<<(ostream& os, const Dog& dog);

};



ostream& operator<<(ostream& os, const Dog& dog)

{

os << dog.m_age<<endl;


return os;

}


int main()

{

cout << min<Dog>(Dog(1), Dog(3), [](const Dog& a, const Dog& b) {return const_cast<Dog&>(a) > b; })<< endl;


//Save();

}


new로 잡은 메모리공간과 스택 공간은 상당한 차이가있는 공간이다.

스택에 잡은 객체를 내가 해지할 수는 없다. 지역변수는 컴퓨터가 담당한다. 나는 생성자를 불리는 일 밖에 못한다.


소멸자는 단순 함수여서 내가 부를 수도 있다. 객체가 사라지는 것과 아무런 차이가 없다.



class Model

{

public:

int size{0};

char* data=nullptr;

public:

Model() { cout << "디폴트 생성\n"; }

Model(const int& num) :size{num}

data = new char[num];  

cout << "(int)생성\n"; 

}

~Model()

{

cout << "소멸자:  " << size << "바이트: " << static_cast<void*>(data) << endl;

if (data != nullptr)

delete[] data;

}

Model(const Model& other)

{

data = other.data;

cout << "= 복사 생성\n";

}

Model operator=(Model& other) 

data = other.data;

cout << "= 복사 생성\n"; 

return  *this; 

}

};


int main()

{

Model a;

Model b{ 1000 };

Model c = b;

//Save();

}



Model a;

스텍에 a를 잡겠어!

시작번지는 널포인터야

Model b{ 1000 };

a와 이어져서 스택에 b를 잡겠어!

메모리 잡은 1000바이트는 힙에 잡히고 시작번지를 기록

Model c = b;

기본 복사 생성자를 썼다면 b의 시작번지를 c에 복사해 오는 얕은 복사를 수행한다.


스택이니까 마지막에 들어온 c가 사라진다. 소멸자에서 힙에 잡힌 메모리를 삭제한다.

다음에 b가 나오면 delete할 메모리가 없어 dangling Pointer, 즉 지울 수 없는 포인터를 지우게 해서 터진다.


Model(const Model& other) :size{other.size}

{

data = new char[size];

memcpy(data, other.data, sizeof(other.data));

cout << "복사 생성\n";

}

Model operator=(const Model& other)

size= other.size ;

data = new char[size];

memcpy(data, other.data, sizeof(other.data));

cout << "= 복사 생성\n"; 

return  *this; 

}


깊은 복사를 하는 복사생성자와 복사 연산자를 만들어야 한다.

모든 것은 자원 확보에서 시작한다.

당신이 자원을 확보하는 클래스를 만든다고 생각해보자.

class X

{
}

클래스를 이렇게 쓰면 컴파일러는 필요하면 자동으로 다음 4개 함수를 만든다.


X() = default;

~X() = default;

X(const X&) = default;

X& operator=(const X&) = default; // copy assignment operator


프로그래머가 꼭 프로그래밍 안해도 꼭 필요하기때문에 자동으로 만든다.

하지만 자원을 할당하는 클래스에서 이 함수들을 하나라도 안한다면 이 클래스는 제대로 사용할 수 없다. 여기에 c++11이후의 이동 기능을 사용하고 싶으면 이동생성자와 이동할당연산자를 제대로 프로그래밍 해야 한다.

X(X&&)

X& operator&(X&&)


'C++' 카테고리의 다른 글

스마트 포인터  (0) 2018.04.05
이동  (2) 2018.03.29
템플릿- 2  (0) 2018.03.19
템플릿  (0) 2018.03.08
다형성, 레퍼런스  (0) 2018.03.05
Comments