[따배C++] 15. 의미론적 이동과 스마트 포인터
Created: June 6, 2021 11:26 AM
Tag: move semantics, r-value references, smart pointers
15.1 이동의 의미와 스마트 포인터 move semantics, smart pointers
// Resource.h
#include <iostream>
class Resource
{
public:
int m_data[100];
public:
Resource()
{
std::cout << "Resource constructed" << std::endl;
}
~Resource()
{
std::cout << "Resource destroyed" << std::endl;
}
};
// ==============================
// AutoPtr.h
#include <iostream>
template<class T>
class AutoPtr
{
public:
T *m_ptr = nullptr;
public:
AutoPtr(T *ptr = nullptr)
: m_ptr(ptr)
{
}
~AutoPtr()
{
if (m_ptr != nullptr) delete m_ptr;
}
// 소유권 이동 구현
AutoPtr(AutoPtr & a)
{
m_ptr = a.m_ptr;
a.m_ptr = nullptr; // 첫번째 포인터를 null로 바꿔버린다
}
AutoPtr &operator = (AutoPtr &a)
{
if (&a == this)
return (*this);
delete m_ptr;
m_ptr = a.m_ptr;
a.m_ptr = nullptr;
return (*this);
}
T &operator*() const { return (*m_ptr); }
T *operator->() const { return (m_ptr); }
bool isNull() const { return (m_ptr == nullptr); }
}
// ==============================
// main.cpp
#include <iostream>
#include "Resource.h"
#include "AutoPtr.h"
using namespace std;
// RAII: resource acquisition is initialization
// 동적할당을 한 부분에서 그것이 해제되어야 한다는 개념
void doSomething()
{
// Resource *res = new Resource; // dull pointer
AutoPtr<Resource> res(new Resource); // smart pointer
// delete res; // <- smart pointer를 사용하기 때문에 필요없음
return ;
}
int main(void)
{
doSomething();
// Auto Pointer의 한계
{
AutoPtr<Resource> res1(new Resource);
AutoPtr<Resource> res2;
cout << std::boolalpha;
cout << res1.m_ptr << endl;
cout << res2.m_ptr << endl; // null
res2 = res1; // <- 문제발생: 소유권의 move가 필요하다! // move semantics
cout << res1.m_ptr << endl;
cout << res2.m_ptr << endl; // 이미 지워진 메모리를 또 지우려고 시도하게 되면 runtime error 발생
}
// syntax vs semantics
// compile vs 실제 내부적 의미
// value semantics(copy semantics)
// reference semantics(pointer)
// move semantics
return (0);
}
💡 syntax vs semantics == compile vs 실제 내부적 의미
// Resource.h
#include <iostream>
class Resource
{
public:
int m_data[100];
public:
Resource()
{
std::cout << "Resource constructed" << std::endl;
}
~Resource()
{
std::cout << "Resource destroyed" << std::endl;
}
};
// ==============================
// AutoPtr.h
#include <iostream>
template<class T>
class AutoPtr
{
public:
T *m_ptr = nullptr;
public:
AutoPtr(T *ptr = nullptr)
: m_ptr(ptr)
{
}
~AutoPtr()
{
if (m_ptr != nullptr) delete m_ptr;
}
// 소유권 이동 구현
AutoPtr(AutoPtr & a)
{
m_ptr = a.m_ptr;
a.m_ptr = nullptr; // 첫번째 포인터를 null로 바꿔버린다
}
AutoPtr &operator = (AutoPtr &a)
{
if (&a == this)
return (*this);
delete m_ptr;
m_ptr = a.m_ptr;
a.m_ptr = nullptr;
return (*this);
}
T &operator*() const { return (*m_ptr); }
T *operator->() const { return (m_ptr); }
bool isNull() const { return (m_ptr == nullptr); }
}
// ==============================
// main.cpp
#include <iostream>
#include "Resource.h"
#include "AutoPtr.h"
using namespace std;
// RAII: resource acquisition is initialization
// 동적할당을 한 부분에서 그것이 해제되어야 한다는 개념
void doSomething()
{
// Resource *res = new Resource; // dull pointer
AutoPtr<Resource> res(new Resource); // smart pointer
// delete res; // <- smart pointer를 사용하기 때문에 필요없음
return ;
}
int main(void)
{
doSomething();
// Auto Pointer의 한계
{
AutoPtr<Resource> res1(new Resource);
AutoPtr<Resource> res2;
cout << std::boolalpha;
cout << res1.m_ptr << endl;
cout << res2.m_ptr << endl; // null
res2 = res1; // <- 문제발생: 소유권의 move가 필요하다! // move semantics
cout << res1.m_ptr << endl;
cout << res2.m_ptr << endl; // 이미 지워진 메모리를 또 지우려고 시도하게 되면 runtime error 발생
}
// syntax vs semantics
// compile vs 실제 내부적 의미
// value semantics(copy semantics)
// reference semantics(pointer)
// move semantics
return (0);
}
1) value semantics (copy semantics)
2) reference semantics (pointer)
3) move semantics
15.2 오른쪽-값 참조 R-value Reference
#include <iostream>
using namespace std;
void doSomething(int &lref)
{
cout << "l-value ref" << endl;
}
void doSomthing(int &&ref)
{
cout << "r-value ref" << endl;
}
// ...
int main(void)
{
int x = 5;
const int cx = 6;
// L-value references
int &lr1 = x; // modifiable l-values
//int &lr2 = cs; // non modifiable l-values // 주석은 문법상 컴파일이 안되는 코드임
//int &lr3 = 5; // r-values // r-values에 대한 reference는 가질 수 없다
const int &lr4 = x; // modifiable l-values
const int &lr5 = cx; // non-modifiable l-values
const int &lr6 = 5; // r-values
// r-value references
//int &&rr1 = x; // modifiable l-values
//int &&rr2 = cx; // non-modifiable l-values
int &&rr3 = 5; // r-values
//const int &&rr4 = x; // modifiable l-values
//const int &&rr5 = cx; // non modifiable l-values
const int &&rr6 = 5; // r-values
// L/R-value reference parameters
doSomething(x); // l-value
doSomething(5); // non l-value == r-value
return (0);
}
Author And Source
이 문제에 관하여([따배C++] 15. 의미론적 이동과 스마트 포인터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@24siefil/따배C-15.-의미론적-이동과-스마트-포인터
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
#include <iostream>
using namespace std;
void doSomething(int &lref)
{
cout << "l-value ref" << endl;
}
void doSomthing(int &&ref)
{
cout << "r-value ref" << endl;
}
// ...
int main(void)
{
int x = 5;
const int cx = 6;
// L-value references
int &lr1 = x; // modifiable l-values
//int &lr2 = cs; // non modifiable l-values // 주석은 문법상 컴파일이 안되는 코드임
//int &lr3 = 5; // r-values // r-values에 대한 reference는 가질 수 없다
const int &lr4 = x; // modifiable l-values
const int &lr5 = cx; // non-modifiable l-values
const int &lr6 = 5; // r-values
// r-value references
//int &&rr1 = x; // modifiable l-values
//int &&rr2 = cx; // non-modifiable l-values
int &&rr3 = 5; // r-values
//const int &&rr4 = x; // modifiable l-values
//const int &&rr5 = cx; // non modifiable l-values
const int &&rr6 = 5; // r-values
// L/R-value reference parameters
doSomething(x); // l-value
doSomething(5); // non l-value == r-value
return (0);
}
Author And Source
이 문제에 관하여([따배C++] 15. 의미론적 이동과 스마트 포인터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@24siefil/따배C-15.-의미론적-이동과-스마트-포인터저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)