5

muszę dynamicznie przydzielać dwuwymiarową tablicę inteligentnych wskaźników, ale składni dla mnie to jest mylące. Muszę to być dynamiczna:Składnia dla dynamicznego przydzielania tablicy 2D inteligentnych wskaźników

std::unique_ptr<someClass> myArray[size1][size2]; 

Więc z tego co rozumiem utworzyć wskaźnik do wskaźnika do typu:

someClass** myArray; //actaully the type is std::unique_ptr<someClass> but I'll just keep it simple 

Następnie przydzielić go zrobić:

myArray* = new someClass*[size1]; 
for(int i = 0; i < size1; i++) 
    myArray[i] = new someClass[size2]; 

Ale to nie używa inteligentnych wskaźników, co oznacza, że ​​będę musiał ręcznie usunąć je później, i nie wiem, jak zrobić te wskaźniki inteligentne wskaźniki;

Typ jest std :: unique_ptr ale potem muszę wskaźnik do wskaźnika do typu, więc próbowałem:

std::unique_ptr<std::unique_ptr<std::unique_ptr<someClass>>> myArray; 

Ale po tym gubię na jak bym go przydzielić. Czy ktoś mógłby mi pomóc?

+4

A 1D 'vector >' powinien być dobrym zamiennikiem dla dwuwymiarowej tablicy inteligentnych wskaźników. – juanchopanza

+1

Ponadto tablice dwuwymiarowe nie są podwójnymi wskaźnikami. –

+2

W C++ "dwuwymiarowa tablica X" jest napisana 'std :: vector >'. –

Odpowiedz

3

Pokażę ci, jak rozwiązać swój problem konkretnie i jak podejść do problemów takich jak ten w ogóle.

W ogóle, podobnie jak każdy problem, że dostaje zbyt skomplikowane, spróbuj rozbicie go. Narzędzie do podziału złożonych deklaracji typów w C i C++ od dawna było "typedef". Oto, w jaki sposób podejść do niej w przypadku definicji typu kaskadowego, takich jak ta, którą posiadasz: wybierz najbardziej wewnętrzny typ owijania, tj. Unique_ptr zawijający twoją klasę i wprowadź typedef dla typu, który chcesz zawinąć. Następnie wykonaj to samo dla typu, który ten typ jest zawijany, aż znajdziesz się w najbardziej zewnętrznym typie.

To stycznie związane tylko pytania, ale chcę wspomnieć, bo można uruchomić w podobnej kwestii jak ta, którą mają teraz z szablonami późniejszych. Ponieważ C++ 11 można wygodniej zdefiniować aliasy dla typów zawierających parametry szablonu z klauzulą ​​"using": http://en.cppreference.com/w/cpp/language/type_alias. Sprawdź ten link, jeśli jest to dla Ciebie interesujące w tym kontekście lub nabierze znaczenia w przyszłości!

Do konkretnego problemu. Funkcja "test_dynamic_2darray1" buduje dwuwymiarową tablicę inteligentnych wskaźników o wymiarach 10x10. Kiedy uruchomisz ten kod, powinieneś zobaczyć 100 linii wyjścia z destruktora, zaraz po tym, gdy zarządzana tablica wychodzi poza zakres.

size_t destructor_count = 0; 
class MyClass { 
    public: 
    ~MyClass() { 
     std::cout << "Destructor call #" << ++destructor_count << std::endl; 
    } 
}; 

typedef std::unique_ptr<MyClass[]> ManagedC; 

void test_dynamic_2darray1() { 
    size_t dimension1 = 10, dimension2 = 10; 

    auto managed_array = std::unique_ptr<ManagedC[]>(new ManagedC[dimension1]); 
    for (size_t i = 0; i < dimension1; ++i) 
     managed_array[i] = ManagedC(new MyClass[dimension2]); 
} 

Porównaj to z tym kodem, w którym nie będzie nazwany destruktory z dynamicznie alokowanych instancji klasy i nie widać wyjścia:

void test_dynamic_2darray2() { 
    size_t dimension1 = 10, dimension2 = 10; 

    auto simple_array = new MyClass*[dimension1]; 
    for (size_t i = 0; i < dimension1; ++i) 
     simple_array[i] = new MyClass[dimension2]; 
} 

Mam nadzieję, że udało nam się odpowiedzieć na to pytanie! :) Daj mi znać, jeśli chcesz, abym coś omawiał! Napisałem też powiązany wpis na blogu, który może Cię zainteresować: http://frankriesecodingblog.blogspot.com/2015/01/performance-of-dynamic-multi.html. Zamieszczam go tutaj, ponieważ pokazuje różne podejścia do wielowymiarowych tablic dynamicznych i analizuje działanie często sugerowanej metody wykorzystania wektorów wektorów.

Last but not least, pozwól mi wspomnieć korzystania z int iteracyjne nad tablic. Mam nadzieję, że nie zmieni się to w moją ulubienicę, ale widzę, że to dużo. Powinieneś prawdopodobnie używać size_t. Czemu? Na przykład na moim 64-bitowym komputerze "int" ma 32 bity, ale adresy reprezentowane przez size_t są 64-bitowe. To niewłaściwe użycie int było przyczyną wielu błędów, w szczególności w przenoszeniu 32-bitowych aplikacji na 64-bitowe komputery.Jeśli potrzebujesz podpisanego typu, dla takich zastosowań, jak przesunięcia między adresami tablicy, lepszym rozwiązaniem będzie prawdopodobnie ptrdiff_t.

+0

Próbowałem zastosować twoje rozwiązanie do mojego problemu, ale pojawia się następujący błąd, gdy próbuję przekazać moją tablicę podwójnych znaków podwójnych do funkcji przetwarzania: 'error C2664: 'functionName': nie można przekonwertować parametru 7 ze 'std :: unique_ptr <_Ty> * 'to' double ** ''. Zasadniczo chciałbym utworzyć podwójną tablicę 2D i przydzielić pamięć, jest pewien kod inicjalizacyjny, a następnie zostaje przekazany do funkcji. W przypadku, gdy funkcja zgłasza wyjątek, chcę użyć inteligentnych wskaźników, aby pomóc w późniejszym oczyszczeniu. – Ben

+0

Domyślam się, że muszę ustawić "wymiar2" (w twoim przykładzie) jako głupie wskaźniki, ale zainicjować je za pomocą inteligentnych wskaźników i przypisując je do tablicy 2D za pomocą .get()? – Ben

2

W ilustracyjnym przykładzie, poniżej jest składni, który może być stosowany w C++ nowoczesny tworzenia i napełniania int 2D tablicę (o rozmiarach 3 o 5) za pomocą inteligentnego wskaźnik (unique_ptr) oraz inne cechy, takie jak make_unique i move().

unique_ptr<unique_ptr<int[]>[]>  smartPtr2D; 
unique_ptr<int[]>     smartPtr1D; 

int dataCounter = 0; 

smartPtr2D = make_unique< unique_ptr<int[]>[] >(3); 
for (int i = 0; i<3; i++) 
{ 
    smartPtr1D = make_unique<int[]>(5); 
    for (int j = 0; j<5; j++) 
    { 
     smartPtr1D[j] = dataCounter; 
     dataCounter++; 
    } 
    smartPtr2D[i] = move(smartPtr1D); 
} 
Powiązane problemy