C++/Library
2021. 3. 24. 10:47
unique_ptr
unique_ptr
<memory>
라이브러리scope를 벗어나면 자동으로 메모리를 해제하므로 메모리 누수를 방지할 수 있다.
예제
main.cpp
#include <iostream>
#include <memory>
#include "Resource.h"
using namespace std;
int main()
{
std::unique_ptr<Resource> res(new Resource(100000000));
}
/* stdout
Resource length constructed
Resource destoryed
*/
Resource.h
#pragma once
#include <iostream>
class Resource
{
public:
int *data_ = nullptr;
unsigned length_ = 0;
Resource()
{
std::cout << "Resource default constructed\n";
}
Resource(unsigned length)
{
std::cout << "Resource length constructed\n";
init(length);
}
Resource(const Resource& res)
{
std::cout << "Resource copy constructed\n";
init(res.length_);
for (unsigned i = 0; i < length_; ++i)
data_[i] = res.data_[i];
}
~Resource()
{
std::cout << "Resource destoryed\n";
if (data_ != nullptr) delete[] data_;
}
void init(unsigned length)
{
data_ = new int[length];
length_ = length;
}
Resource& operator = (Resource& res)
{
std::cout << "Resource copy assignment\n";
if (&res == this) return *this;
if (data_ != nullptr) delete[] data_;
init(res.length_);
for (unsigned i = 0; i < length_; ++i)
data_[i] = res.data_[i];
return *this;
}
void print()
{
for (unsigned i = 0; i < length_; ++i)
std::cout << data_[i] << ' ';
std::cout << std::endl;
}
void setAll(const int& v)
{
for (unsigned i = 0; i < length_; ++i)
data_[i] = v;
}
};
make_unique
unique_ptr
를 안전하게 반환하는 함수main.cpp
#include <iostream> #include <memory> #include "Resource.h" using namespace std; auto doSomething() { //return std::unique_ptr<Resource>(new Resource(5)); return std::make_unique<Resource>(5); // 이걸 더 추천 } int main() { auto res1 = doSomething(); res1->setAll(5); std::unique_ptr<Resource> res2; if (res1 != nullptr) { cout << "res1 : "; res1->print(); } if (res2 != nullptr) { cout << "res2 : "; res2->print(); } cout << boolalpha; cout << "res1 : " << static_cast<bool>(res1) << endl; cout << "res2 : " << static_cast<bool>(res2) << endl; cout << '\n'; res2 = std::move(res1); if (res1 != nullptr) { cout << "res1 : "; res1->print(); } if (res2 != nullptr) { cout << "res2 : "; res2->print(); } cout << "res1 : " << static_cast<bool>(res1) << endl; cout << "res2 : " << static_cast<bool>(res2) << endl; } /* stdout stderr Resource length constructed res1 : 5 5 5 5 5 res1 : true res2 : false res2 : 5 5 5 5 5 res1 : false res2 : true Resource destoryed */
아래의 명령은 에러가 발생한다.
main.cpp
res2 = res1;
error C2280: 'std::unique_ptr<Resource,std::default_delete<Resource>> &std::unique_ptr<Resource,std::default_delete<Resource>>::operator =(const std::unique_ptr<Resource,std::default_delete<Resource>> &)': attempting to reference a deleted function
unique_ptr
는 말 그대로 포인터를 단독 사용하기 위해 쓰는 클래스이므로, 라이브러리 자체에서 복사 대입(copy assignment,operator =
)을 delete한 것이다.
copy constructor
도 delete
한 상태임을 보여주는 예제
main.cpp
#include <iostream>
#include <memory>
#include "Resource.h"
using namespace std;
auto doSomething(std::unique_ptr<Resource> res) // 에러
{
res->setAll(10);
}
int main()
{
auto res1 = std::make_unique<Resource>(5);
res1->setAll(1);
res1->print();
doSomething(res1);
res1->print();
}
error C2280: 'std::unique_ptr<Resource,std::default_delete<Resource>>::unique_ptr(const std::unique_ptr<Resource,std::default_delete<Resource>> &)': attempting to reference a deleted function
- 에러 메시지를 통해 라이브러리에서 복사 생성자(copy constructor)를
delete
한 것임을 알 수 있다.
이 예제에서
doSomething(std::move(res1))
과 같이R-value
로 넘기면,doSomething
함수 내부로unique_ptr
인res1
이 옮겨간다.해당 함수의
scope
밖으로 나오는 순간(함수가 끝나고 스택이 되감길 때)unique_ptr
의 특성으로res
가 사라진다.글로 설명하는 것보다 예제를 보는게 쉽다.
main.cpp
#include <iostream> #include <memory> #include "Resource.h" using namespace std; auto doSomething(std::unique_ptr<Resource> res) { res->setAll(10); } int main() { auto res1 = std::make_unique<Resource>(5); res1->setAll(1); res1->print(); cout << boolalpha << static_cast<bool>(res1) << endl; doSomething(std::move(res1)); cout << static_cast<bool>(res1) << endl; } /* stdout stderr Resource length constructed 1 1 1 1 1 true Resource destoryed false */
get()
unique_ptr
로 가지고 있는 포인터를 반환한다.
<memory>
// STRUCT TEMPLATE _Get_deleter_pointer_type
template <class _Ty, class _Dx_noref, class = void>
struct _Get_deleter_pointer_type { // provide fallback
using type = _Ty*;
};
...
template <class _Ty, class _Dx /* = default_delete<_Ty> */>
class unique_ptr {
public:
using pointer = typename _Get_deleter_pointer_type<_Ty, remove_reference_t<_Dx>>::type;
...
_NODISCARD pointer get() const noexcept {
return _Mypair._Myval2;
}
...
private:
template <class, class>
friend class unique_ptr;
_Compressed_pair<_Dx, pointer> _Mypair;
};
<xmemory>
template <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>>
class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty first
public:
_Ty2 _Myval2;
...
};
'C++ > Library' 카테고리의 다른 글
C++ weak_ptr (0) | 2021.03.24 |
---|---|
C++ shared_ptr (0) | 2021.03.24 |
C++ std::move (0) | 2021.03.24 |
C++ 출력 스트림 끊기 (0) | 2021.03.24 |
C++ std::exception (0) | 2021.03.22 |