예시코드)
https://github.com/GbLeem/CPP_Study/tree/main/NoCode
39.cpp ~ 42.cpp
#include<iostream>
#include<memory>
class Cat
{
public:
Cat()
:mAge{0}
{
std::cout << "cat constructor" << std::endl;
}
~Cat() noexcept
{
std::cout << "cat desturctor" << std::endl;
}
private:
int mAge;
};
int main()
{
//raw pointer
Cat* catRPtr = new Cat{ 3 };
delete catRPtr;
//smart pointer
//delete가 필요없다.
std::unique_ptr<Cat> catPtr = std::make_unique<Cat>(3);
return 0;
}
#include<iostream>
#include<vector>
#include<memory>
class Cat
{
//위의 Cat과 같은 구조
};
void foo()
{
std::cout<< "foo function" <<std::endl;
std::vector<Cat> cat(5);
std::cout<< "foo function end" <<std::endl;
}
int main()
{
std::cout << "before foo" << std::endl;
foo();
std::cout << "after foo" << std::endl;
}
예시 코드
main 함수에서 주석 처리된 부분은 raw pointer를 이용하는 부분
-> 프로그램 작성 시 실수로 잘못된 동작을 하도록 만들 가능성이 높다.
-> 주석 처리된 부분의 구조
smart pointer(unique_ptr) 이용
-> 개발자가 소유권에 대한 생각을 하지 않아도 되기 때문에 쉽고 안전한 코드 작성 가능
#include<iostream>
#include<memory>
class Cat
{
public:
Cat()
:mAge{ 0 }
{
std::cout << "Cat constructor" << std::endl;
}
~Cat()
{
std::cout << "Cat desturctor" << std::endl;
}
private:
int mAge;
};
void foo(Cat*ptr)
{
Cat* fooPtr = ptr;
}
int main()
{
//Cat* catRPtr = new Cat();
//Cat* catRPtr1 = catRPtr;
//foo(catRPtr);
//delete catRPtr;
std::unique_ptr<Cat>catSPtr = std::make_unique<Cat>();
//std::unique_ptr<Cat>catSPtr1 = catSPtr; 컴파일 오류-> 안정성 좋아짐
std::unique_ptr<Cat>catSPtr2 = std::move(catSPtr); //ok -> ownership을 넘겨줌
return 0;
}
class Animal
{...};
class Tiger : public Animal
{...};
class Lion : public Animal
{...};
class Zoo
{
public:
Zoo(int n)
{
if (n == 1)
//mAnimal = new Tiger();
mAnimal = std::make_unique<Tiger>(); //better
-> rule of three 를 고려하지 않아도 된다
else
//mAnimal = new Lion();
mAnimal = std::make_unique<Lion>(); //better
}
private:
//Animal* mAnimal;
std::unique_ptr<Animal> mAnimal; //better
};
#include<iostream>
#include<memory>
class Cat
{
public:
Cat()
:mAge{ 0 }
{
std::cout << "Cat constructor" << std::endl;
}
~Cat()
{
std::cout << "Cat desturctor" << std::endl;
}
private:
int mAge;
};
class Dog
{
public:
Dog()
{
std::cout << "Dog constructor" << std::endl;
}
~Dog()
{
std::cout << "Dog desturctor" << std::endl;
}
};
int main()
{
//raw pointer
//몇개의 포인터가 Cat 오브젝트를 가리키고 있는지 알 수가 없다. -> bad
//Cat* catptr1 = new Cat();
//Cat* catptr2 = catptr1;
//delete catptr1;
//shared_ptr 의 좋은 예시
std::shared_ptr<Cat> catPtr1 = std::make_shared<Cat>();
std::cout << "count: " << catPtr1.use_count() << std::endl; //1
std::shared_ptr<Cat>catPtr2 = catPtr1;
std::cout << "count: " << catPtr1.use_count() << std::endl; //2
}
class Dog
{
public:
Dog()
{
std::cout << "Dog constructor" << std::endl;
}
~Dog()
{
std::cout << "Dog desturctor" << std::endl;
}
std::shared_ptr<Dog> mVar;
std::shared_ptr<Dog> mFriend;
};
int main()
{
//Shared pointer의 leak 예시
std::shared_ptr<Dog>mPtr = std::make_shared <Dog>();
mPtr->mVar = mPtr; //자기 자신을 가리킨다.
std::cout << "count : " << mPtr.use_count() << std::endl; //2
//자주하는 실수 예시
std::shared_ptr<Dog> dogPtr1 = std::make_unique<Dog>();
std::shared_ptr<Dog> dogPtr2 = std::make_unique<Dog>();
dogPtr1->mFriend = dogPtr2;
dogPtr2->mFriend = dogPtr1;
//destructor가 호출 X, by circular reference -> memory leak
}
#include<iostream>
#include<memory>
class Cat
{
public:
Cat()
:mAge{1}
{
std::cout << "Cat constructor" << std::endl;
}
~Cat()
{
std::cout << "Cat desturctor" << std::endl;
}
void speak()
{
std::cout << "Im cat.." << std::endl;
}
private:
int mAge;
};
int main()
{
std::weak_ptr<Cat> wPtr;
{
std::shared_ptr<Cat> sPtr = std::make_shared<Cat>();
wPtr = sPtr;
std::cout << "count: " << sPtr.use_count() << std::endl; //1
if (const auto spt = wPtr.lock()) //weak pointer를 사용
{
std::cout << "count: " << sPtr.use_count() << std::endl; //2
spt->speak();
}
}
return 0;
}
class Dog
{
public:
Dog(int n)
:mVar{ std::make_unique<int>(n) }
{
std::cout << "constructor" << std::endl;
}
//직접 만든 copy constructor
Dog(const Dog& other)
:mVar{ std::make_unique<int>(other.mVar) }
{}
~Dog()
{
std::cout << "destructor" << std::endl;
}
private:
std::unique_ptr<int> mVar;
};
int main()
{
Dog dog1;
//copy constructor 구현 이전에..
//Dog dog2{dog1}; 컴파일 에러
//dog3 = dog1; 컴파일 에러
}
class Dog
{
public:
explicit Dog(int n)
:mVar{ std::make_shared<int>(n) }
{
std::cout << "constructor" << std::endl;
}
~Dog() noexcept
{
std::cout << "destructor" << std::endl;
}
Dog clone() const //deep copy interface
{
Dog temp{ *mVar };
return temp;
}
private:
std::shared_ptr<int> mVar;
};
int main()
{
const Dog dog1{ 2 };
//의도에 맞게 사용
const Dog dog2{dog1};
const Dog dog3{ dog1.clone() }; //deep copy
}