IT 개발 노트/PROGRAMMING

[C++] std::shared_ptr

뺄칸 2024. 12. 10. 14:45
  • 효율적인 메모리 관리를 위해 만들어진 객체입니다.
  • 참조 카운트 방식으로 메모리 해제를 결정합니다. (0이 되면 해제)

기본 사용법

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>();
    
    std::cout << "memory address : " 
        << ptr1 << std::endl;
    
    std::cout << "memory value : " 
        <<  *ptr1 << std::endl;
    
    return 0;
}


/* OUTPUT
memory address : 0x55744002aec0
memory value : 0
*/

 

참조 카운트 움직임

#include <iostream>
#include <memory>

void RefCountTest(std::shared_ptr<int> param) {
    std::cout << "ref count after param transmission : " 
        << param.use_count() << std::endl; 

    std::shared_ptr<int> localPtr = param;

    std::cout << "ref count after local reference : "
        << param.use_count() << std::endl << std::endl;
}

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>();
    std::cout << "memory address : " 
        << ptr1 << std::endl;
    
    std::cout << "memory value : " 
        <<  *ptr1 << std::endl << std::endl;

    
    RefCountTest(ptr1);
    std::cout << "ref count after finished function : " 
        <<  ptr1.use_count() << std::endl; 
    
    return 0;
}

/* OUTPUT
memory address : 0x55746e45dec0
memory value : 0

ref count after param transmission : 2
ref count after local reference : 3

ref count after finished function : 1
*/

 

소멸자 중복 호출에서 벗어나기

#include <iostream>
#include <memory>

class duplicationDestroy {
public:
    duplicationDestroy() {
        data = new int[10];
        std::cout << "Called Constructor!!" << std::endl;
    }

    ~duplicationDestroy() {
        std::cout << "Called Destroy." << std::endl;
        delete[] data;
    }
private:
    int* data;
};

int main() {
    duplicationDestroy* allocData = new duplicationDestroy();
    
    std::shared_ptr<duplicationDestroy> ptr1(allocData);
    std::shared_ptr<duplicationDestroy> ptr2(allocData);

    std::cout << ptr1.use_count() << std::endl;
    std::cout << ptr2.use_count() << std::endl;
    
    return 0;
}

/* OUTPUT
Called Constructor!!
1
1
Called Destroy.
Called Destroy.

메모리 해제를 했는데 다시 하기 때문에 에러이고,
이로인해 스레드 방식의 운영이면 Exception이 발생이 가능합니다.
*/
  • std::enable_from_this<T> 상속 받아서 사용하면 됩니다.
#include <iostream>
#include <memory>

class duplicationDestroy : public std::enable_shared_from_this<duplicationDestroy> {
public:
    duplicationDestroy() {
        data = new int[10];
        std::cout << "Called Constructor!!" << std::endl;
    }

    ~duplicationDestroy() {
        std::cout << "Called Destroy." << std::endl;
        delete[] data;
    }
private:
    int* data;
};

int main() {
    //duplicationDestroy* allocData = new duplicationDestroy();

    std::shared_ptr<duplicationDestroy> ptr1 = std::make_shared<duplicationDestroy>();
    std::cout << "ptr1 use_count : " 
        << ptr1.use_count() << std::endl;
    
    std::shared_ptr<duplicationDestroy> ptr2 = ptr1;

    std::cout << "ptr1 use_count : "
        << ptr1.use_count() << std::endl;
    std::cout << "ptr2 use_count : "
        << ptr2.use_count() << std::endl;

    return 0;
}


/* OUTPUT
Called Constructor!!
ptr1 use_count : 1
ptr1 use_count : 2
ptr2 use_count : 2
Called Destroy.
*/

 

순환 참조라면 std::weak_ptr을 이용하자.

#include <iostream>
#include <memory>

class SharedTest {
    std::weak_ptr<SharedTest> ptr1;
public:
    SharedTest() {
        std::cout << "initialize resource!!" << std::endl;
    }
    ~SharedTest() {
        std::cout << "Destroy resource!" << std::endl;
    }

    void SetPtr(std::shared_ptr<SharedTest> param) {
        ptr1 = param;
    }
};

int main() {
    std::shared_ptr<SharedTest> pa1 = std::make_shared<SharedTest>();
    std::shared_ptr<SharedTest> pa2 = std::make_shared<SharedTest>();
    pa1->SetPtr(pa2);    
    pa2->SetPtr(pa1);
    std::cout << pa1.use_count() << std::endl;
    std::cout << pa2.use_count() << std::endl;
    
    return 0;
}

/* OUTPUT
initialize resource!!
initialize resource!!
1
1
Destroy resource!
Destroy resource!
*/