본문 바로가기

C

c++ heap 메모리 생성, 해제, unique_ptr, shared_ptr

unique ptr은 exclusive ownership을 보장함.

 

c++ heap 메모리 생성, 해제

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <memory>
#include <vector>
 
class Cat
{
public:
    explicit Cat(int age) :mAge{ age }
    {
        std::cout << "cat constructor" << std::endl;
    }
    ~Cat() noexcept
    {
        std::cout << "cat destructor" << std::endl;
    }
private:
    int mAge;
};
 
 
class ThiefCat
{
public:
    explicit ThiefCat() : mAge{ 0 }
    {
        std::cout << "Thiefcat constructor" << std::endl;
    }
    ~ThiefCat() noexcept
    {
        std::cout << "Thiefcat destructor" << std::endl;
    }
private:
    int mAge;
};
 
 
void foo()
{
    std::cout << "foo function" << std::endl;
    std::unique_ptr<Cat> catPtr = std::make_unique<Cat>(3);
    std::cout << "foo function end" << std::endl;
};
 
int main()
{
    //Cat* catPtr = new Cat{ 3 };
    //delete catPtr;
    std::cout << "before scope" << std::endl;
    {
        std::unique_ptr<Cat> catPtr = std::make_unique<Cat>(3);
    }
    std::cout << "after scope" << std::endl;
 
    foo();
 
    ThiefCat* thiefcats = new ThiefCat[5];
    delete[] thiefcats;
    
    //vector 쓰면 leak 안 생김
    
    
    std::vector<ThiefCat> thiefcats1(10);
    return 0;
}
cs

 

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
///
///    //std::unique_ptr<Cat> catPtr1 = catPtr;
    // unique pointer는 복사가 불가능함
    // 그러나 move는 가능함
    // class에서 member variable로 unique_ptr쓸때 좋음
/// 
#include <iostream>
#include <memory>
class Animal
{
};
 
class Cat : public Animal
{
public:
    Cat() :mAge{ 0 }
    {
        std::cout << "cat constructor" << std::endl;
    }
    ~Cat()
    {
        std::cout << "cat destructor" << std::endl;
    }
private:
    int mAge;
};
 
class Dog : public Animal
{
};
 
class Zoo : public Animal
{
public:
    Zoo(int n)
    {
        // enum class를 사용하는 것이 더 올바르다
        if (n == 1)
        {
            mAnimal = std::make_unique<Cat>();
        }
        else
        {
            mAnimal = std::make_unique<Dog>();
        }
    }
    // 멤버 Variable에 포인터가 있으면 copy, move 다 정의해 주어야 함
    // unique_ptr을 사용함으로써 destructor, delete, copy, move를 개발자가
    // 생각할 필요가 없어짐
private:
    std::unique_ptr<Animal> mAnimal;
};
 
void foo(Cat * ptr)
{
    Cat* fooPtr = ptr;
}
 
int main()
{
    //Cat* catPtr = new Cat();
    //Cat* Catptr1 = catPtr;
    //foo(catPtr);
    //delete catPtr;
 
    std::unique_ptr<Cat> catptr = std::make_unique<Cat>();
    //std::unique_ptr<Cat> catPtr1 = catPtr;
    // unique pointer는 복사가 불가능함
    // 그러나 move는 가능함
    std::unique_ptr<Cat> catptr1 = std::move(catptr);
    
 
    return 0;
}

 

Shared Pointer

shared_ptr은 하나의 object를 여러개의 pointer가 가르킬 수 있음.

shared_ptr은 object를 가르키는 pointer가 증가할 때마다 reference count가 증가한다.

그러다가 reference count가 0이 되는 순간 heap 메모리에서 제거되게 된다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <memory>
class Cat 
{
public:
    Cat() :mAge{ 0 }
    {
        std::cout << "cat constructor" << std::endl;
    }
    ~Cat()
    {
        std::cout << "cat destructor" << std::endl;
    }
    std::shared_ptr<Cat> mVar;
    std::shared_ptr<Cat> mFriend;
private:
    int mAge;
};
 
int main()
{
    /// <summary>
    ///  몇개의 pointer가 object를 가르키는지 명확하지 않음
    /// shared pointer를 쓰자!
    /// </summary>
    /// <returns></returns>
    Cat* catPtr = new Cat();
    Cat* catPtr1 = catPtr;
    delete catPtr;
    /// <summary>
    /// 
    ///
    /// </summary>
    /// <returns></returns>
    std::shared_ptr<Cat> catPtr_shared = std::make_shared<Cat>();
    std::cout << "count: " << catPtr_shared.use_count() << std::endl;
    
    std::shared_ptr<Cat> catPtr_shared1 = catPtr_shared;
    std::cout << "count: " << catPtr_shared.use_count() << std::endl;
    
 
    /// <summary>
    /// shared_ptr을 사용하지만 memory leak이 발생할 수도 있음.
    /// </summary>
    /// <returns></returns>
    std::shared_ptr<Cat> mPtr = std::make_shared<Cat>();
    mPtr->mVar = mPtr;
    std::cout << "count: " << mPtr.use_count() << std::endl;
    // count는 2 이며 memory leak 발생!(Destructor 미호출)
 
 
    // Destructor 미호출
    // pkitty, pnabi의 reference count가 서로 1이 되어서
    // Destructor 미호출, memory leak 발생함
    // circular reference
    // Java, c#, python은 Gabage collector가 memory leak 없애줌
    // Gc - "Mark and sweep" 에서 메모리 해제 방법 참고
 
    std::shared_ptr<Cat> pKitty = std::make_shared<Cat>();
    std::shared_ptr<Cat> pNabi = std::make_shared<Cat>();
    pKitty->mFriend = pNabi;
    pNabi->mFriend = pKitty;
 
    return 0;
}

unique_ptr, shared_ptr에서의 주의점

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <memory>
 
// Shared ptr을 쓰면 memory leak을 피할 수 없다.
// Cat has shared ptr member라고 표기해 줘야 한다
// 그리고 shared ptr이라면 copy가 어려우므로
// clone 함수를 별도로 만드는 게 좋다 (Ex)opencv)
class Cat
{public:
 
    //explicit Cat(int n) : mVar{ std::make_unique<int>(n) }
    explicit Cat(int n) : mVar{ std::make_shared<int>(n) }
    {
        std::cout << "cat Constructor" << std::endl;
    }
    // unique ptr만 쓰면 대입 연산이 불가능하므로(first created ownership)
    // 복사 생성자를 만들어서 써야 한다.
    Cat(const Cat& other) :mVar{ std::make_unique<int>(*other.mVar) }
    {
        std::cout << "other cat constructed" << std::endl;
    }
    // shared ptr을 위한 clone 함수 생성
    Cat clone()
    {
        Cat tmp{ *mVar };
        return tmp;
    }
    ~Cat() noexcept
    {
        std::cout << "cat destructor" << std::endl;
    }
private:
    //std::unique_ptr<int> mVar;
 
    std::shared_ptr<int> mVar;
    // 만약 shared_ptr이라면 memory leak을 피할 수 없다.
    // 따라서 클래스 위에
    // Cat has shared ptr member라고 표기해 줘야 한다
};
 
int main()
{
    const Cat kitty{ 1 };
    //Cat nabi;
    //nabi = kitty; // error(unique pointer이므로)
    const Cat nabi{ kitty };
}

 

 

 

'C' 카테고리의 다른 글

c++ lambda expression, capture =, &  (0) 2021.06.23
c++ weak pointer 정리  (0) 2021.06.23
c++ const, explicit  (0) 2021.06.23
c++ class function overloading, 연산자(operator) 임의 지정  (0) 2021.06.23
C++ class copy move constructor, instructor  (0) 2021.06.23