On this page
article
C++ Reference Counting
Reference Counting
상황
addRef(), release()로 refcnt를 관리하고 있었을 때 실수로 delete하는 것을 막고 싶다.
지역 변수를 만들고 release()하는 것을 막고 싶다.
대응
- Protected destructor 사용
- 외부에서 직접
delete하는 것을 방지 - 객체를 힙에만 생성 가능하게 설계
예시
class Car {
int refcnt = 0;
public:
void addRef() { ++refcnt; }
void release() {
if (--refcnt == 0)
delete this;
}
protected:
~Car() { std::cout << "~Car" << std::endl; }
};
int main() {
// Car c;
// c.release();
Car* p1 = new Car;
p1->addRef();
// delete p1;
p1->release();
}
Reference Counting 2
상황
Base가 되는 RefCount 클래스를 만들어서 관리하고 싶다.
하지만 그렇게 하면 Derived 클래스의 소멸자가 호출되지 않는 문제 발생.
대응
- **CRTP(Curiously Recurring Template Pattern)**으로 해결
addRef,release를const함수로 만들고refcnt를 **mutable**로 선언const함수 안에서는this도const로 취급되므로const_cast필요template hoisting/thin template적용하여 code bloat 방지
예시
class RefCountBase {
protected:
mutable int refcnt = 0;
public:
void addRef() const { ++refcnt; }
};
template<typename T>
class RefCount {
public:
void release() const {
if (--refcnt == 0)
delete static_cast<const T*>(this);
}
};
참고
std::atomic<int> refcnt로 멀티스레드 환경 대응 가능++refcnt→refcnt.fetch_add(1, std::memory_order_relaxed)--refcnt→refcnt.fetch_sub(1, std::memory_order_acq_rel)
멀티스레드 프로그래밍 시 memory ordering도 고려해야 한다.
Reference Counting 3
shared_ptr의 문제점
- 참조계수를 관리하는 관리 객체가 2개 이상 생성될 위험
예시
class Truck {
public:
~Truck() { std::cout << "~Truck" << std::endl; }
};
int main() {
std::shared_ptr<Truck> sp1(new Truck);
std::shared_ptr<Truck> sp2 = sp1;
Truck* p1 = new Truck;
std::shared_ptr<Truck> sp3(p1);
std::shared_ptr<Truck> sp4(p1); // 문제: sp3, sp4가 각각 별도의 관리 객체 생성
}
std::make_shared를 사용하면 참조계수가 관리 객체 안에 포함되도록 할 수 있지만,
이걸 원하지 않는 경우 별도의 refcount가 포함된 클래스를 만들어서 사용하기도 한다.
std::advance
상황
반복자를 5칸 전진하고 싶다.
p = p + 5는vector에서는 가능하지만list에서는 불가능++p; ++p; ++p; ++p; ++p;는 되지만 비효율적
대응
std::advance(p, 5) 사용
vector에서는p = p + 5처럼 동작list에서는++p여러 번 반복처럼 동작
구현 방법의 변화
std::advance의 구현 방법은 C++ 표준에 따라 변화:
- C++98: tag dispatching
- C++11:
enable_if - C++17:
if constexpr - C++20:
concept및requiresclauses
이를 통해 시대별 C++의 코딩 방식 변화와 함께 설계 원리를 이해할 수 있다.