5

Ho bisogno di allocare dinamicamente un array bidimensionale di puntatori intelligenti ma la sintassi per esso mi confonde. Ho bisogno di questo per essere dinamica:Sintassi per l'allocazione dinamica di un array 2D di puntatori intelligenti

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

Quindi, da quello che ho capito io creo un puntatore a un puntatore al tipo:

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

Poi di destinare lo faccio io:

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

Ma questo non usa puntatori intelligenti, il che significa che dovrò cancellarlo manualmente in un secondo momento, e non so come fare questi puntatori puntatori intelligenti;

Il tipo è std :: unique_ptr ma poi ho bisogno di un puntatore a un puntatore al tipo, così ho provato:

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

Ma dopo questo Mi sono perso su come avrei allocare esso. Per favore qualcuno potrebbe aiutarmi?

+4

Un 1D 'vettore >' dovrebbe essere un buon sostituto per una matrice 2D di puntatori intelligenti. – juanchopanza

+1

Inoltre, gli array bidimensionali non sono doppi puntatori. –

+2

In C++, "array bidimensionale di X" è scritto 'std :: vector >'. –

risposta

3

Ti mostrerò come risolvere il tuo problema in modo specifico e come affrontare problemi come questo in generale.

In generale, proprio come qualsiasi problema che diventa troppo complesso, provare a scomposizione. Lo strumento per scomporre le dichiarazioni di tipo complesso in C e C++ è stato a lungo il "typedef". Ecco come ci si avvicina per le definizioni di tipi in cascata come quella che si sta facendo: prendi il tipo di wrapping più interno, cioè il unique_ptr che avvolge la tua classe e crea un typedef per il tipo che vuoi avvolgere. Quindi, continua a fare lo stesso per il tipo che quel tipo sta eseguendo il wrapping, finché non sei al tipo più esterno.

Questo è tangenzialmente correlato alla tua domanda, ma voglio menzionarlo, perché potresti imbatterti in un problema simile a quello che stai avendo ora con i modelli successivi. Dal momento che in C++ 11 è possibile definire più facilmente anche alias per tipi che coinvolgono parametri di template con la clausola "using": http://en.cppreference.com/w/cpp/language/type_alias. Vai a controllare quel link se ti interessa in questo contesto o diventa rilevante in futuro!

Per il vostro problema specifico. La funzione "test_dynamic_2darray1" crea un array bidimensionale 10x10 di puntatori intelligenti. Quando si esegue questo codice, è necessario visualizzare 100 righe dell'output dal distruttore, solo quando l'array gestito non rientra nell'ambito.

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]); 
} 

Confronti che, per questo codice, qualora non vengano chiamati i distruttori delle istanze di classe allocati dinamicamente e si vede alcun output:

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]; 
} 

Spero di essere stato in grado di rispondere alla tua domanda! :) Fammi sapere se vuoi che elabori qualcosa! Ho anche scritto un post sul blog correlato l'altro giorno che potrebbe interessarti: http://frankriesecodingblog.blogspot.com/2015/01/performance-of-dynamic-multi.html. Lo sto postando qui, perché mostra diversi approcci ad array dinamici multidimensionali e esamina le prestazioni del metodo spesso suggerito di utilizzare vettori di vettori.

Ultimo ma non meno importante, lasciatemi menzionare l'utilizzo di int per iterare su array. Spero che questo non si trasformi in un mio vero problema, ma vedo che questo è stato fatto molto. Probabilmente dovresti usare size_t. Perché? Ad esempio, sulla mia macchina a 64 bit "int" è a 32 bit, ma gli indirizzi, rappresentati da size_t, sono a 64 bit. Questo uso improprio di int è stato la causa di molti bug, in particolare per il porting di applicazioni a 32 bit su macchine a 64 bit.Se hai bisogno di un tipo firmato, per usi come offset tra gli indirizzi di array, un uso migliore sarebbe probabilmente ptrdiff_t.

+0

Ho provato ad applicare la soluzione al mio problema, ma sto riscontrando il seguente errore quando provo a passare la mia matrice 2D di doppi a una funzione per l'elaborazione: 'errore C2664: 'functionName': impossibile convertire il parametro 7 da 'std :: unique_ptr <_Ty> * 'a' double ** ''. Fondamentalmente mi piacerebbe creare il doppio array 2D e allocare la memoria, c'è un codice di inizializzazione e poi viene passato a una funzione. Nel caso in cui la funzione genera un'eccezione, voglio utilizzare i puntatori intelligenti per chiarire in seguito. – Ben

+0

Immagino che quello che devo fare sia impostare 'dimension2' (nel tuo esempio) come puntatori stupidi, ma inizializzarli usando puntatori intelligenti e assegnandoli all'array 2D usando il .get()? – Ben

2

Come esempio illustrativo, sotto è la sintassi che può essere utilizzato in C++ moderna per la creazione e il riempimento di un array di int 2D (di misura 3 da 5) utilizzando puntatore intelligente (unique_ptr) e altre caratteristiche come make_unique e 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); 
} 
Problemi correlati