일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- 상태
- 알고리즘
- 반응형 웹
- Codility
- 확률
- c
- 통신사할인
- skt membership
- Photoshop
- SK바이오사이언스
- pandas
- transform
- 포토샵
- Javascript
- 소수
- grid
- 강화학습
- c++
- stl
- REM
- 백준
- JSX
- 미디어 쿼리
- CSS
- Gap
- 수학
- box-sizing
- react
- spring
- float
Archives
- Today
- Total
sliver__
[Mastering C++ Programming] - weak_ptr / Circular dependency 본문
728x90
- 지금까지 예제를 통해 shared_ptr의 긍정적인 측면에 대해 논의했습니다.
- 그러나 응용 프로그램 디자인에 순환 종속성이 있는 경우 shared_ptr이 메모리 정리에 실패합니다.
- 응용 프로그램 설계를 리팩터링하여 순환 종속성을 피하거나 weak_ptr을 사용하여 순환 종속성 문제를 해결할 수 있습니다.
- https://www.youtube.com/watch?v=SVTLTK5gbDc. ( circular dependency 설명 )
- A, B, C의 세 가지 클래스가 있다고 가정합니다.
- 클래스 A와 B에는 C의 인스턴스가 있고 C에는 A와 B의 인스턴스가 있습니다.
- 여기에 설계 문제가 있습니다.
- A는 C에 의존하고 C도 A에 의존합니다.
- 마찬가지로 B는 C에 의존하고 C도 B에 의존합니다.
- 코드 예제는 아래와 같습니다.
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
using namespace std;
class C;
class A {
private:
shared_ptr<C> ptr;
public:
A() {
cout << "\nA constructor" << endl;
}
~A() {
cout << "\nA destructor" << endl;
}
void setObject ( shared_ptr<C> ptr ) {
this->ptr = ptr;
}
};
class B {
private:
shared_ptr<C> ptr;
public:
B() {
cout << "\nB constructor" << endl;
}
~B() {
cout << "\nB destructor" << endl;
}
void setObject ( shared_ptr<C> ptr ) {
this->ptr = ptr;
}
};
class C {
private:
shared_ptr<A> ptr1;
shared_ptr<B> ptr2;
public:
C(shared_ptr<A> ptr1, shared_ptr<B> ptr2) {
cout << "\nC constructor" << endl;
this->ptr1 = ptr1;
this->ptr2 = ptr2;
}
~C() {
cout << "\nC destructor" << endl;
}
};
int main ( ) {
shared_ptr<A> a( new A() );
shared_ptr<B> b( new B() );
shared_ptr<C> c( new C( a, b ) );
a->setObject ( shared_ptr<C>( c ) );
b->setObject ( shared_ptr<C>( c ) );
return 0;
}
- 결과는 아래와 같습니다.
/a.out
A constructor
B constructor
C constructor
- Destructor가 호출이 안된것을 볼 수 있는데 각 shared_ptr의 객체를 삭제하기 위해서는 dependency가 있는 객체가 삭제되어야 하기 때문입니다.
- 이전 출력에서 shared_ptr을 사용했지만 개체 A, B 및 C에서 사용하는 메모리가 할당 해제되지 않았음을 확인할 수 있습니다.
- 호출되는 각 클래스의 소멸자를 보지 못했기 때문입니다.
- 그 이유는 shared_ptr이 내부적으로 참조 카운팅 알고리즘을 사용하여 공유 객체를 소멸시켜야 하는지 여부를 결정하기 때문입니다.
- shared_ptr은 자신이 참조하고 있는 객체(메모리 주소)에 대해 reference counting을 함으로써, 객체의 수명에 직접적으로 관여합니다.
- shared_ptr 객체 하나가 소멸되더라도, 동일한 메모리 주소를 참조하고 있는 다른 shared_ptr 객체가 있으면 참조하고 있던 메모리 주소의 객체는 소멸되지 않습니다.
- 객체 C를 삭제하지 않으면 객체 A를 삭제할 수 없기 때문에 여기서는 실패합니다.
- 개체 C를 삭제하지 않으면 개체 B를 삭제할 수 없습니다.
- 또한 개체 A와 B를 삭제하지 않으면 개체 C를 삭제할 수 없습니다.
- 마찬가지로 객체 C를 삭제하지 않으면 객체 A를 삭제할 수 없고 객체 C를 삭제하지 않으면 객체 B를 삭제할 수 없습니다.
- 결론은 이것이 순환 종속성 설계 문제라는 것입니다.
- 이 문제를 해결하기 위해 C++11부터 C++는 weak_ptr을 도입했습니다.
- weak_ptr 스마트 포인터는 strong reference가 아닙니다.
- 따라서 참조된 개체는 shared_ptr과 달리 언제든지 삭제할 수 있습니다.
- 코드 예제는 아래와 같습니다.
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
using namespace std;
class C;
class A {
private:
weak_ptr<C> ptr;
public:
A() {
cout << "\nA constructor" << endl;
}
~A() {
cout << "\nA destructor" << endl;
}
void setObject ( weak_ptr<C> ptr ) {
this->ptr = ptr;
}
};
class B {
private:
weak_ptr<C> ptr;
public:
B() {
cout << "\nB constructor" << endl;
}
~B() {
cout << "\nB destructor" << endl;
}
void setObject ( weak_ptr<C> ptr ) {
this->ptr = ptr;
}
};
class C {
private:
shared_ptr<A> ptr1;
shared_ptr<B> ptr2;
public:
C(shared_ptr<A> ptr1, shared_ptr<B> ptr2) {
cout << "\nC constructor" << endl;
this->ptr1 = ptr1;
this->ptr2 = ptr2;
}
~C() {
cout << "\nC destructor" << endl;
}
};
int main ( ) {
shared_ptr<A> a( new A() );
shared_ptr<B> b( new B() );
shared_ptr<C> c( new C( a, b ) );
a->setObject ( weak_ptr<C>( c ) );
b->setObject ( weak_ptr<C>( c ) );
return 0;
}
- 결과는 아래와 같습니다.
./a.out
A constructor
B constructor
C constructor
C destructor
B destructor
++) Reference
1) [C++] shared_ptr circular reference - 스마트포인터 크로스 참조 피하기 : 네이버 블로그 (naver.com)
[C++] shared_ptr circular reference - 스마트포인터 크로스 참조 피하기
아... 저번에 치명적인 메모리 누수 문제를 만났다고 했잖아요? '모든 곳에서 shared_ptr을 썼는데 이상하...
blog.naver.com
2) [c++] weak_ptr :: 웅웅이의 지식창고 (tistory.com)
[c++] weak_ptr
이번장에서는 weak_ptr에 대해서 알아 보도록 합니다. shared_ptr를 구현하면서 참조 카운트에 영향을 받지 않는 스마트 포인터가 필요했는데 weak_ptr을 사용하면 shared_ptr가 관리하는 자원(메모리)을
jungwoong.tistory.com
728x90
'CS > C++' 카테고리의 다른 글
[Mastering C++ Programming] - How to write a multithreaded application using the native C++ thread feature (0) | 2022.12.08 |
---|---|
[Mastering C++ Programming] - Creating threads with the pthreads library (0) | 2022.12.08 |
[Mastering C++ Programming] - shared_ptr (0) | 2022.12.07 |
[Mastering C++ Programming] - unique_ptr (0) | 2022.12.07 |
[Mastering C++ Programming] - auto ptr (0) | 2022.12.07 |
Comments