development

할당 된 배열을 보유하는 unique_ptr을 만드는 적절한 방법

big-blog 2021. 1. 10. 19:48
반응형

할당 된 배열을 보유하는 unique_ptr을 만드는 적절한 방법


무료 저장소에 할당 된 배열을 보유하는 unique_ptr을 만드는 올바른 방법은 무엇입니까? Visual Studio 2013은 기본적으로이를 지원하지만 Ubuntu에서 gcc 버전 4.8.1을 사용하면 메모리 누수와 정의되지 않은 동작이 발생합니다.

다음 코드를 사용하여 문제를 재현 할 수 있습니다.

#include <memory>
#include <string.h>

using namespace std;

int main()
{
    unique_ptr<unsigned char> testData(new unsigned char[16000]());

    memset(testData.get(),0x12,0);

    return 0;
}

Valgrind는 다음과 같은 출력을 제공합니다.

==3894== 1 errors in context 1 of 1:
==3894== Mismatched free() / delete / delete []
==3894==    at 0x4C2BADC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3894==    by 0x400AEF: std::default_delete<unsigned char>::operator()(unsigned char*) const (unique_ptr.h:67)
==3894==    by 0x4009D0: std::unique_ptr<unsigned char, std::default_delete<unsigned char> >::~unique_ptr() (unique_ptr.h:184)
==3894==    by 0x4007A9: main (test.cpp:19)
==3894==  Address 0x5a1a040 is 0 bytes inside a block of size 16,000 alloc'd
==3894==    at 0x4C2AFE7: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3894==    by 0x40075F: main (test.cpp:15)

T[]전문화 사용 :

std::unique_ptr<unsigned char[]> testData(new unsigned char[16000]());

이상적인 세계에서는 잠재적 인 예외 안전 함정을 피하기 위해 명시 적으로를 사용 new하여를 인스턴스화 할 필요가 없습니다 unique_ptr. 이를 위해 C ++ 14는 std::make_unique함수 템플릿을 제공합니다 . 자세한 내용은 이 훌륭한 GOTW 를 참조하십시오. 구문은 다음과 같습니다.

auto testData = std::make_unique<unsigned char[]>(16000);

어레이 버전 사용 :

auto testData = std::unique_ptr<unsigned char[]>{ new unsigned char[16000] };

또는 C ++ 14를 사용하면 더 나은 형식 (VS2013에 이미 있음) :

auto testData = std::make_unique<unsigned char[]>( 16000 );

가장 좋은 방법은 std::vector<unsigned char>대신 사용하는 것입니다.

#include <vector>
#include <string>

using namespace std;

int main()
{
    vector<unsigned char> testData(0x12, 0); // replaces your memset
    // bla    
}

장점은 오류 발생 가능성이 훨씬 적고 손쉬운 반복, 삽입, 용량에 도달했을 때 자동 재 할당과 같은 모든 종류의 기능에 액세스 할 수 있다는 것입니다.

한 가지주의 할 점이 있습니다. 데이터를 많이 이동하는 경우 데이터 std::vector의 시작 부분이 아니라 크기와 용량도 추적하므로 비용이 조금 더 듭니다.

참고 : memset0 카운트 인수로 호출하기 때문에 아무것도 수행하지 않습니다.


바보 같아, 무슨 말인지 설명해 줄게

class Object {
private :
    static int count;
public :
    Object() {
        cout << "Object Initialized " << endl;
        count++;
    }
    ~Object() {
        cout << "Object destroyed " << endl;
    }
    int print()
    {
        cout << "Printing" << endl;
        return count;
    }
};

int Object::count = 0;

int main(int argc,char** argv)
{
    // This will create a pointer of Object
    unique_ptr<Object> up2 = make_unique<Object>();  
    up2->print();
    // This will create a pointer to array of Objects, The below two are same. 
    unique_ptr<Object[]> up1 = std::make_unique<Object[]>(30);
    Object obj[30];
    cout << up1.get()[8].print();
    cout << obj[8].print();

    // this will create a array of pointers to obj. 
        unique_ptr<Object*[]> up= std::make_unique<Object*[]>(30);
        up.get()[5] = new Object();
        unique_ptr<Object> mk = make_unique<Object>(*up.get()[5]);
        cout << up.get()[5]->print();

        unique_ptr<unique_ptr<Object>[]> up3 =  std::make_unique<unique_ptr<Object>[]>(20);
        up3.get()[5] = make_unique<Object>();

    return 0;
}

Objective of the post is that there are hidden small subtle things you need to understand. Creating array of objects is same as object array of unique_ptr. It will make difference only when you pass it in the argument. Creating array of object pointers of unique_ptr is also not very useful. So only below two you need to use in most scenarios.

unique_ptr<Object> obj;
//and 
unique_ptr<unique_ptr<Object>[]>= make_unique<unique_ptr<Object>[]>(20);

unsigned int size=16000;
std::unique_ptr<unsigned char[], std::default_delete<unsigned char[]>> pData(new unsigned char[size]);

ReferenceURL : https://stackoverflow.com/questions/21377360/proper-way-to-create-unique-ptr-that-holds-an-allocated-array

반응형