C++11 학습 노트(3) - 일반 도구(켜기)(중요 기능 포함) 스마트 포인터 스마트 포인터)

1. 쌍

C++11에서 std::pair는 두 값을 단일 단위로 결합하는 데 사용되는 템플릿 클래스입니다. 서로 다른 유형의 두 값을 쌍으로 연결할 수 있으며 값 쌍에 대한 액세스 및 조작을 제공합니다.

std::pair의 정의

template<class T1, class T2>
struct pair{
    
    
	T1 first;
	T2 second;
};

약간의 사용법

만들기 및 초기화:

std::pair 개체는 생성자 또는 중괄호로 묶인 초기화 목록을 사용하여 만들고 초기화할 수 있습니다. 예를 들어:

std::pair<int, std::string> myPair(42, "Hello");
std::pair<double, bool> anotherPair = {
    
    3.14, true};

방문회원

std::pair 개체의 멤버는 .first 및 .second를 통해 액세스할 수 있습니다. 예를 들어:

std::pair<int, std::string> myPair(42, "Hello");
int x = myPair.first;
std::string str = myPair.second;

비교 및 정렬

std::pair는 비교 작업을 수행할 수 있으며 .first 및 .second 값에 따라 비교할 수 있습니다. std::pair 개체는 컨테이너에서 정렬할 수 있습니다. 예를 들어:

std::pair<int, std::string> pair1(42, "Hello");
std::pair<int, std::string> pair2(10, "World");

bool result = (pair1 < pair2);  // 比较操作
std::vector<std::pair<int, std::string>> myVector = {
    
    pair1, pair2};
std::sort(myVector.begin(), myVector.end());  // 容器排序

사용 예:

std::pair는 여러 값을 반환하는 함수와 두 값을 단일 단위로 전달해야 하는 상황에서 자주 사용됩니다. 예를 들어:

std::pair<int, std::string> getPerson() {
    
    
    int age = 25;
    std::string name = "John";
    return std::make_pair(age, name);
}

std::pair<int, int> divideAndRemainder(int dividend, int divisor) {
    
    
    int quotient = dividend / divisor;
    int remainder = dividend % divisor;
    return {
    
    quotient, remainder};
}

make_pair()

유형을 작성하지 않고 쌍 개체를 생성할 수 있습니다. 예를 들면 다음과 같습니다.

std::pair<int, char> myPair(42, "Hello");
std::make_pair(42, "Hello");

작동 기능

여기에 이미지 설명 삽입

std::pair는 두 값을 결합하는 편리한 방법을 제공하며 다양한 시나리오에서 사용할 수 있습니다. 코드를 단순화하고 코드 가독성을 향상시키기 위해 C++에서 일반적으로 사용되는 도구 중 하나입니다.

2.튜플

튜플은 쌍의 개념을 확장하여 각 유형을 지정할 수 있는 여러 요소를 포함합니다.

튜플의 정의

template<typename... Types>
class tuple;

튜플 예

#include <iostream>
#include <tuple>

int main() {
    
    
    // 创建一个包含整数、字符串和浮点数的元组
    std::tuple<int, std::string, double> myTuple(42, "Hello", 3.14);

    // 访问元组中的元素
    int intValue = std::get<0>(myTuple);
    std::string stringValue = std::get<1>(myTuple);
    double doubleValue = std::get<2>(myTuple);

    // 修改元组中的元素
    std::get<0>(myTuple) = 100;

    // 使用tie函数将元组的元素解包到变量中
    
    int a;
    std::string b;
    double c;
    std::tie(a, b, c) = myTuple;
		//std::tie(a, std::ignore, c) = myTuple;忽略某些元素
    // 打印元组的元素
    std::cout << "Tuple elements: " << a << ", " << b << ", " << c << std::endl;
		//c++11也可直接输出myTuple
    return 0;
}

작동 기능

여기에 이미지 설명 삽입

표준::튜플_크기

std::tuple의 크기를 가져오는 데 사용됩니다.

#include <iostream>
#include <tuple>

int main() {
    
    
    std::tuple<int, std::string, double> myTuple;

    std::cout << "Tuple size: " << std::tuple_size<decltype(myTuple)>::value << std::endl;

    return 0;
}

출력 결과는 다음과 같습니다. 튜플 크기: 3, std::tuple에 세 개의 요소가 있음을 나타냅니다.

std::tuple_element

std::tuple의 지정된 위치에서 요소 유형을 가져오는 데 사용됩니다.


#include <iostream>
#include <tuple>

int main() {
    
    
    using MyTuple = std::tuple<int, std::string, double>;

    std::tuple_element<1, MyTuple>::type myElement;

    std::cout << "Element type: " << typeid(myElement).name() << std::endl;

    return 0;
}

출력 결과는 다음과 같습니다. 요소 유형: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE, std::tuple의 두 번째 요소 유형이 std::string임을 나타냅니다.

std::tuple_cat

여러 std::tuple을 하나의 큰 std::tuple로 결합하는 데 사용됩니다.


#include <iostream>
#include <tuple>

int main() {
    
    
    std::tuple<int, std::string> tuple1(42, "Hello");
    std::tuple<double> tuple2(3.14);

    auto combinedTuple = std::tuple_cat(tuple1, tuple2);

    std::cout << "Combined tuple size: " << std::tuple_size<decltype(combinedTuple)>::value << std::endl;

    return 0;
}

출력 결과는 결합된 튜플 크기: 3입니다. 즉, 튜플1과 튜플2를 결합한 후 세 개의 요소를 포함하는 std::tuple을 얻습니다.

쌍과 튜플

std::pair에서 std::tuple로 변환

std::pair는 std::make_tuple 함수를 사용하여 std::tuple로 변환될 수 있습니다.

#include <iostream>
#include <tuple>

int main() {
    
    
    std::pair<int, double> myPair(42, 3.14);

    std::tuple<int, double> myTuple = std::make_tuple(myPair.first, myPair.second);

    std::cout << "Tuple elements: " << std::get<0>(myTuple) << ", " << std::get<1>(myTuple) << std::endl;

    return 0;
}

위의 예에서 std::pair<int, double> 유형의 객체 myPair가 있고 std::make_tuple을 사용하여 std::tuple<int, double> 유형의 myTuple 객체로 변환할 수 있습니다.

std::tuple에서 std::pair로 변환

std::get 함수를 사용하여 std::tuple의 요소를 추출하고 이러한 요소를 사용하여 std::pair를 만들 수 있습니다.


#include <iostream>
#include <tuple>

int main() {
    
    
    std::tuple<int, double> myTuple(42, 3.14);

    std::pair<int, double> myPair = std::make_pair(std::get<0>(myTuple), std::get<1>(myTuple));

    std::cout << "Pair elements: " << myPair.first << ", " << myPair.second << std::endl;

    return 0;
}

위의 예에서 우리는 std::tuple<int, double> 유형의 myTuple 개체가 있고 std::get 함수를 사용하여 해당 요소를 추출하고 이러한 요소를 사용하여 std::pair<int, double> 유형의 개체 myPair를 만들 수 있습니다.

3.스마트 포인터***

포인터는 c/c++의 중요한 기능이지만 사용 중 댕글링(dangling), 다중 삭제, 리소스 누수 등의 문제가 자주 발생하는데 이러한 문제를 피하는 일반적인 방법은 스마트 포인터를 사용하는 것입니다.
C++11부터 표준 라이브러리는 shared_ptr 및 unique_ptr의 두 가지 유형의 스마트 포인터를 제공하지만 auto_ptr은 더 이상 사용되지 않으며 <memory>에 정의되어 있습니다.

공유_ptr

동적으로 할당된 메모리를 보다 안전하고 편리하게 관리하기 위해 스마트 포인터의 일종인 std::shared_ptr을 사용합니다. std::shared_ptr은 참조 카운팅을 사용하여 리소스 소유자를 추적하고 더 이상 필요하지 않을 때 리소스를 자동으로 해제합니다.

다음은 std::shared_ptr의 기본 사용법과 예입니다.

std::shared_ptr 개체를 만듭니다.

std::shared_ptr 개체는 std::make_shared 함수를 사용하거나 std::shared_ptr 생성자를 직접 사용하여 만들 수 있습니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
    std::shared_ptr<int> ptr2(new int(100));

    std::cout << *ptr1 << std::endl; // 输出:42
    std::cout << *ptr2 << std::endl; // 输出:100

    return 0;
}

위의 예에서 std::make_shared를 사용하여 정수 값을 포함하는 std::shared_ptr 개체 ptr1을 만들고 std::shared_ptr의 생성자를 사용하여 다른 std::shared_ptr 개체 ptr2를 만듭니다.

공유 소유 리소스:

동일한 리소스의 소유권을 공유하도록 하나의 std::shared_ptr을 다른 std::shared_ptr에 할당할 수 있습니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
    std::shared_ptr<int> ptr2 = ptr1;

    std::cout << *ptr1 << std::endl; // 输出:42
    std::cout << *ptr2 << std::endl; // 输出:42

    return 0;
}

위의 예에서 ptr1을 ptr2에 할당했으며 이제 둘 다 동일한 정수 리소스를 가리키고 해당 리소스의 소유권을 공유합니다.

참조 카운팅 및 리소스 릴리스:

std::shared_ptr은 참조 카운팅을 사용하여 리소스 소유자 수를 추적합니다. 마지막 std::shared_ptr이 소멸되거나 새 값이 할당되면 참조 횟수가 감소하고 리소스를 해제해야 하는지 확인합니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
    std::shared_ptr<int> ptr2 = ptr1;
    std::shared_ptr<int> ptr3 = ptr1;

    std::cout << *ptr1 << std::endl; // 输出:42
    std::cout << *ptr2 << std::endl; // 输出:42
    std::cout << *ptr3 << std::endl; // 输出:42

    ptr1.reset();

    std::cout << std::boolalpha;
    std::cout << "ptr1 is nullptr: " << (ptr1 == nullptr) << std::endl; // 输出:true
    std::cout << "ptr2 is nullptr: " << (ptr2 == nullptr) << std::endl; // 输出:false
    std::cout << "ptr3 is nullptr: " << (ptr3 == nullptr) << std::endl; // 输出:false

    return 0;
}

위의 예에서는 모두 동일한 정수 리소스를 가리키는 세 개의 std::shared_ptr 개체 ptr1, ptr2 및 ptr3을 만들었습니다. ptr1이 reset 함수를 호출하면 더 이상 리소스를 소유하지 않고 참조 횟수가 감소하고 리소스가 해제되지만 ptr2 및 ptr3은 여전히 ​​유효하며 리소스를 소유합니다.

std::shared_ptr은 get(기본 포인터 반환), use_count(참조 횟수 반환), unique(유일한 소유자인지 확인) 등과 같은 다른 유용한 멤버 함수도 제공합니다.

std::shared_ptr을 사용하면 메모리 누수 및 현수 포인터와 같은 문제를 효과적으로 방지하고 편리한 리소스 관리 메커니즘을 제공할 수 있습니다. 그러나 순환 참조 문제가 발생하지 않도록 주의하십시오. 리소스가 해제되지 않을 수 있기 때문입니다.

오물 소각로

std::shared_ptr의 소멸자는 템플릿 매개변수로 지정된 삭제자에 의해 실행됩니다. 삭제 동작은 사용자 지정 삭제자를 제공하여 사용자 지정할 수 있습니다.

deleter는 std::shared_ptr의 참조 횟수가 0이 될 때 리소스 할당 해제를 수행하는 호출 가능한 개체입니다. 삭제자는 함수 포인터, 함수 개체, 람다 식 또는 사용자 지정 유형의 개체일 수 있습니다.

다음은 사용자 정의 삭제기를 사용하는 예입니다.

#include <iostream>
#include <memory>

// 自定义删除器
struct CustomDeleter {
    
    
    void operator()(int* ptr) {
    
    
        std::cout << "Custom deleter is called" << std::endl;
        delete ptr;
    }
};

int main() {
    
    
    std::shared_ptr<int> ptr(new int(42), CustomDeleter());

    return 0;
}

위의 예에서는 사용자 정의 삭제 동작을 구현하기 위해 괄호 연산자를 오버로드하는 CustomDeleter라는 구조를 정의합니다. 기본 함수에서 std::shared_ptr의 생성자를 사용하여 std::shared_ptr 개체 ptr을 만들고 사용자 지정 deleter를 매개 변수로 전달합니다.

std::shared_ptr의 참조 횟수가 0이 되면 사용자 지정 삭제자의 괄호 연산자가 호출되어 리소스를 해제하고 정의한 사용자 지정 삭제 동작을 수행합니다. 이 예에서 사용자 정의 삭제기는 메시지를 인쇄하고 정수에 대한 포인터를 삭제합니다.

커스텀 삭제자를 제공할 때 삭제자가 포인터 유형과 호환되고 적절한 리소스 해제 규칙을 따르는지 확인해야 합니다. 삭제기를 사용자 지정하면 특정 요구 사항을 충족하는 보다 유연한 리소스 관리 및 삭제 동작을 달성할 수 있습니다.

다른 작업

여기에 이미지 설명 삽입여기에 이미지 설명 삽입

weak_ptr

C++11은 std::shared_ptr이 유발할 수 있는 순환 참조 문제를 해결하기 위해 스마트 포인터 유형으로 std::weak_ptr를 도입했습니다. std::weak_ptr은 std::shared_ptr이 관리하는 객체에 대한 약한 참조를 참조 횟수를 늘리지 않고 객체가 파괴되는 것을 방지하지 않고 허용합니다.

다음은 std::weak_ptr의 기본 사용법과 예입니다.

std::weak_ptr 객체 생성

std::weak_ptr 개체는 std::shared_ptr 개체를 std::weak_ptr로 캐스팅하여 만들 수 있습니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
    std::weak_ptr<int> weakPtr = sharedPtr;

    // 输出:42
    if (auto lockedPtr = weakPtr.lock()) {
    
    
        std::cout << *lockedPtr << std::endl;
    } else {
    
    
        std::cout << "Resource has been released" << std::endl;
    }

    return 0;
}

위의 예제에서는 정수 리소스를 관리하기 위해 std::shared_ptr 객체 sharedPtr을 생성하고 std::weak_ptr로 변환하여 std::weak_ptr 객체 weakPtr을 생성했습니다. std::weak_ptr로 캐스팅해도 리소스의 참조 횟수가 증가하지 않습니다.

std::weak_ptr이 유효한지 확인하고 리소스에 액세스

lock() 함수는 std::weak_ptr이 유효한지 확인하고 리소스에 대한 공유 액세스 권한을 얻는 데 사용할 수 있습니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::weak_ptr<int> weakPtr;

    {
    
    
        std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
        weakPtr = sharedPtr;

        // 输出:42
        if (auto lockedPtr = weakPtr.lock()) {
    
    
            std::cout << *lockedPtr << std::endl;
        } else {
    
    
            std::cout << "Resource has been released" << std::endl;
        }
    }

    // 输出:"Resource has been released"
    if (auto lockedPtr = weakPtr.lock()) {
    
    
        std::cout << *lockedPtr << std::endl;
    } else {
    
    
        std::cout << "Resource has been released" << std::endl;
    }

    return 0;
}

위의 예에서 우리는 std::shared_ptr 개체 sharedPtr을 범위에 만들고 std::weak_ptr 개체 weakPtr로 변환했습니다. 범위가 끝나면 sharedPtr이 소멸되고 리소스가 해제됩니다. 이후 코드에서는 weakPtr이 유효한지 확인하고 lock() 함수를 호출하여 리소스에 액세스합니다. weakPtr이 유효하면 lock() 함수는 유효한 std::shared_ptr 객체를 반환하고, 그렇지 않으면 null 포인터를 반환합니다.

리소스 보기

만료()

std::weak_ptr이 만료되었는지 확인하는 데 사용됩니다(즉, 가리키는 리소스가 해제되었는지 여부). 리소스가 해제된 경우 true를 반환하고 그렇지 않으면 false를 반환합니다.

use_count()

std::weak_ptr과 동일한 리소스를 얻는 데 사용되는 유효한 std::shared_ptr 개체의 수입니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
    std::weak_ptr<int> weakPtr = sharedPtr;

    // 输出:1
    std::cout << "use_count: " << sharedPtr.use_count() << std::endl;

    if (weakPtr.expired()) {
    
    
        std::cout << "Resource has been released" << std::endl;
    } else {
    
    
        // 输出:42
        std::cout << "Value: " << *weakPtr.lock() << std::endl;
    }

    sharedPtr.reset();

    // 输出:0
    std::cout << "use_count: " << weakPtr.use_count() << std::endl;

    if (weakPtr.expired()) {
    
    
        std::cout << "Resource has been released" << std::endl;
    } else {
    
    
        std::cout << "Value: " << *weakPtr.lock() << std::endl;
    }

    return 0;
}

위의 예제에서는 정수 리소스를 관리하기 위해 std::shared_ptr 객체 sharedPtr을 생성하고 이를 std::weak_ptr 객체 weakPtr로 변환하여 약한 참조를 생성했습니다. use_count() 함수를 사용하여 sharedPtr과 동일한 리소스를 공유하는 유효한 std::shared_ptr 객체의 수를 가져옵니다. if 문에서 우리는 expired() 함수를 사용하여 weakPtr이 만료되었는지 확인한 다음 lock() 함수를 사용하여 유효한 std::shared_ptr 객체를 가져오고 그 값을 출력합니다. 후속 코드에서는 reset() 함수를 호출하여 sharedPtr을 비우고 리소스를 해제하고 weakPtr이 만료되었는지 확인합니다.

std::weak_ptr은 참조 횟수를 늘리지 않으므로 use_count() 함수를 호출하면 리소스를 공유하는 유효한 std::shared_ptr 개체의 수가 반환됩니다.

다른 작업

여기에 이미지 설명 삽입

std::weak_ptr을 사용하면 std::shared_ptr이 유발할 수 있는 순환 참조 문제를 피할 수 있고 리소스의 수명 주기를 보다 유연하게 관리할 수 있습니다.

unique_ptr

std::unique_ptr은 독점 소유권을 가진 스마트 포인터입니다. 즉, 한 번에 하나의 std::unique_ptr만 포인터가 가리키는 개체를 소유할 수 있습니다. unique_ptr이 소멸되면 그것이 가리키는 개체는 자동으로 소멸됩니다.

다음은 std::unique_ptr의 기본 사용법과 예입니다.

std::unique_ptr 객체 생성

std::unique_ptr 개체는 std::make_unique 함수를 사용하거나 std::unique_ptr 생성자를 직접 사용하여 만들 수 있습니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::unique_ptr<int> uniquePtr1 = std::make_unique<int>(42);
    std::unique_ptr<int> uniquePtr2(new int(100));

    // 输出:42
    std::cout << *uniquePtr1 << std::endl;

    // 输出:100
    std::cout << *uniquePtr2 << std::endl;

    return 0;
}

위의 예에서는 std::make_unique 함수와 생성자를 사용하여 두 개의 std::unique_ptr 개체 uniquePtr1 및 uniquePtr2를 만들어 두 개의 정수 리소스를 관리합니다. std::make_unique는 C++14에서 도입된 함수이므로 C++11을 사용하는 경우 std::unique_ptr의 생성자를 직접 사용할 수 있습니다.

소유권 이전 실행

std::unique_ptr은 배타적 소유권의 특징이 있으며 이동 의미를 통해 하나의 std::unique_ptr에서 다른 std::unique_ptr로 소유권을 이전할 수 있습니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::unique_ptr<int> uniquePtr1 = std::make_unique<int>(42);
    std::unique_ptr<int> uniquePtr2;

    uniquePtr2 = std::move(uniquePtr1);

    // 输出:42
    std::cout << *uniquePtr2 << std::endl;

    return 0;
}

위의 예에서는 std::move를 사용하여 uniquePtr1의 소유권을 uniquePtr2로 이전했습니다. 이렇게 하면 uniquePtr2는 이제 원래 리소스를 소유하고 uniquePtr1은 더 이상 리소스를 소유하지 않습니다.

사용자 정의 삭제기 사용

可以通过提供自定义删除器来指定std::unique_ptr在释放资源时的行为。删除器是一个函数对象或函数指针,用于定义资源释放的方式。
#include <iostream>
#include <memory>

struct CustomDeleter {
    
    
    void operator()(int* ptr) {
    
    
        std::cout << "Deleting resource: " << *ptr << std::endl;
        delete ptr;
    }
};

int main() {
    
    
    std::unique_ptr<int, CustomDeleter> uniquePtr(new int(42));

    // 输出:42
    std::cout << *uniquePtr << std::endl;

    return 0;
}

위의 예에서는 사용자 지정 삭제기 CustomDeleter를 사용하여 std::unique_ptr 개체 uniquePtr을 만들었습니다. uniquePtr이 파괴되면 사용자 지정 삭제자가 호출되어 리소스를 해제할 책임이 있습니다.

std::unique_ptr은 단일 소유권으로 개체를 관리하는 데 적합한 경량 스마트 포인터를 제공하여 효율적인 메모리 관리 및 안전한 리소스 릴리스를 제공합니다.

배열에 대해

C++은 배열을 삭제하기 위해 delete[]를 사용해야 하는데, C++은 포인터가 단일 객체를 가리키는지 배열을 가리키는지 구분할 수 없기 때문에 포인터가 자동으로 삭제되면 오류가 발생하는데 이를 위해 표준 라이브러리에서 특별한 버전을 제공한다.
C++11에서는 std::unique_ptr의 배열 버전, 즉 동적으로 할당된 배열 개체를 관리하는 데 사용되는 std::unique_ptr<T[]>가 도입되었습니다.

다음은 동적 배열을 관리하는 std::unique_ptr의 예입니다.

#include <iostream>
#include <memory>

int main() {
    
    
    std::unique_ptr<int[]> uniquePtr(new int[5]);

    for (int i = 0; i < 5; i++) {
    
    
        uniquePtr[i] = i + 1;
    }

    for (int i = 0; i < 5; i++) {
    
    
        std::cout << uniquePtr[i] << " ";
    }

    // 输出:1 2 3 4 5
    std::cout << std::endl;

    return 0;
}

위의 예에서 std::unique_ptr<int[]>를 사용하여 std::unique_ptr 객체 uniquePtr을 생성하여 5개의 정수를 포함하는 동적 배열을 관리합니다. 배열 첨자 연산자 []를 사용하여 배열의 요소에 액세스하고 수정할 수 있습니다. uniquePtr이 파괴되면 동적 배열이 차지하는 메모리를 자동으로 해제합니다.

std::unique_ptr<T[]>는 기존 배열을 가리키는 대신 new T[]를 통해 동적으로 할당된 배열을 관리하는 데만 적합하다는 점에 유의해야 합니다. 이 버전은 '*' 및 '->' 연산자를 제공하지 않습니다. std::unique_ptr<T[]>를 사용할 때 수동으로 delete[]를 호출하여 메모리를 해제할 필요가 없으며 std::unique_ptr이 자동으로 메모리 해제를 처리합니다. 또한 이 버전은 서로 다른 유형 간의 직접 변환을 지원하지 않으며 파생 요소 유형에 대한 포인터를 허용하지 않습니다.

다른 작업

여기에 이미지 설명 삽입

auto_ptr

std::auto_ptr은 동적으로 할당된 개체를 관리하기 위해 C++98 표준에서 도입한 스마트 포인터입니다. 그러나 std::auto_ptr은 C++11부터 사용되지 않으며 일부 버그와 안전하지 않은 동작으로 인해 새 코드에 권장되지 않습니다.
다음은 std::auto_ptr에 대한 몇 가지 중요한 참고 사항입니다.

소유권 이전

std::unique_ptr과 달리 std::auto_ptr은 소유권 이전을 지원합니다. 즉, 리소스 소유권을 한 std::auto_ptr에서 다른 std::auto_ptr로 이전할 수 있습니다. 이것은 원래 std::auto_ptr이 소유권을 이전한 후 더 이상 리소스를 소유하지 않음을 의미합니다.

어레이는 지원되지 않습니다.

std::auto_ptr은 단일 개체 관리에만 적합하며 동적으로 할당된 배열 관리는 지원하지 않습니다.

삭제자 제한 사항

std::auto_ptr은 기본 삭제자만 지원하며 삭제자를 사용자 지정할 수 없습니다. 즉, std::auto_ptr이 파괴되면 리소스를 해제하기 위해 delete만 호출됩니다.

안전하지 않은 복사 시맨틱

전통적인 복사 의미 대신 이동 의미를 사용하는 std::auto_ptr의 복사 의미에 문제가 있습니다. 이로 인해 원본 std::auto_ptr이 복사 후 리소스 소유권을 잃게 되어 리소스가 반복적으로 릴리스될 수 있습니다.

따라서 독점 소유권의 경우 std::unique_ptr, 공유 소유권의 경우 std::shared_ptr, 순환 참조 문제 해결을 위한 std::weak_ptr과 같이 C++11에서 도입한 더 안전하고 강력한 스마트 포인터 유형을 사용하는 것이 좋습니다. 이러한 스마트 포인터 유형은 더 나은 의미론과 더 강력한 유형 검사를 제공하고 더 나은 리소스 관리를 가능하게 하며 더 나은 메모리 안전성을 제공합니다.

다시 채우다

메모리 오버헤드

원시 포인터와 비교하여 스마트 포인터는 일반적으로 특정 메모리 오버헤드를 발생시킵니다. 스마트 포인터 개체는 일반적으로 참조 횟수와 같은 추가 데이터 멤버를 포함하며 이는 더 많은 메모리를 차지할 수 있습니다. 대부분의 경우 이 오버헤드는 무시할 수 있지만 리소스가 매우 제한된 임베디드 시스템과 같은 특수 환경의 경우 스마트 포인터 사용을 신중하게 고려해야 합니다.

일부 상황에 적합하지 않음

스마트 포인터는 모든 상황에 대한 일반적인 솔루션이 아닙니다. C 인터페이스와의 상호 작용, 외부 리소스 처리 등과 같은 일부 특정 애플리케이션 시나리오에서는 리소스를 수동으로 관리해야 할 수 있으며 스마트 포인터를 사용하는 것은 적합하지 않습니다.

시맨틱 차이 및 주의 사항

서로 다른 유형의 스마트 포인터는 의미 체계와 동작이 다르므로 사용 방법에 대한 이해와 주의가 필요합니다. 예를 들어 std::shared_ptr의 공유 소유권은 추가 오버헤드 및 스레드 안전 문제를 일으킬 수 있는 반면 std::unique_ptr은 독점 소유권 시나리오에 적합합니다. 또한 스마트 포인터를 사용할 때는 순환 참조, 널 포인터 검사 및 잠재적인 성능 영향과 같은 문제에 주의를 기울여야 합니다.

스마트 포인터에는 결함과 주의 사항이 있지만 대부분의 경우 편리하고 안전하며 신뢰할 수 있는 리소스 관리 방법을 제공합니다. 스마트 포인터를 사용할 때 의미와 동작을 이해하고 선택하여 특정 애플리케이션 시나리오와 함께 사용해야 합니다.

추천

출처blog.csdn.net/qq_44616044/article/details/131184594