2017-04-26 3 views
2

J'essaie de créer un pointeur vide vers un objet de classe et de l'initialiser dans une fonction. Malheureusement, le membre du tableau de la classe ne peut pas échapper à la fonction, c'est-à-dire qu'il n'est pas accessible après l'initialisation.Pointeur vide vers un objet de classe: Initialisation dans une fonction

Dans le code ci-dessous, le premier appel à imprimer des positions (à l'intérieur de la fonction d'initialisation) fonctionne correctement, cependant, le deuxième appel à imprimer des positions de l'extérieur de la fonction d'initialisation échoue. J'ai le sentiment que l'objet tableau créé dans la fonction d'initialisation est détruit et non transmis mais je ne suis pas sûr et je ne sais pas non plus comment le réparer.

Toute aide serait grandement appréciée.

#include <iostream> 
#include <iomanip> 
#include <string> 


class Atoms 
{ 
    double * positions; 
    int nAtoms; 

    public: 
     // Standard constructor prividing a pre-existant array 
     Atoms(int nAtoms, double * positionsArray) 
     { 
      this->nAtoms = nAtoms; 
      this->positions = positionsArray; 
     } 

     // Print positions to screen 
     void print_positions() 
     { 
      std::cout<< "nAtoms: " << this->nAtoms << std::endl; 
      int nDim = 3; 
      for (int i = 0; i < nAtoms; i++) 
      { 
       for (int j = 0; j < nDim; j++) 
       { 
        std::cout << std::setw(6) << this->positions[i * nDim + j] << " "; 
       } 
       std::cout << std::endl; 
      } 
      std::cout << std::endl; 
     } 

}; 


void initialize_Atoms_void_pointer(void ** voidAtomsPointer) 
{ 
    //Create a new instance of Atoms by a pointer 
    int numAtoms = 5; 
    int numDim = 3; 
    int elemN = numAtoms * numDim; 
    double data_array[elemN]; 

    for (int i = 0; i < numAtoms; i++) 
    for (int j = 0; j < numDim; j++) 
    { 
     data_array[i * numDim + j] = i * numDim + j + 10; 
    } 
    Atoms *atoms = new Atoms(numAtoms, data_array); 

    // Set the vPointer that the void pointer points to a pointer to Atoms object 
    *voidAtomsPointer = static_cast<void *>(atoms); 

    //Test call 
    std::cout << std::endl << "Initializing atoms" << std::endl; 
    static_cast<Atoms *>(*voidAtomsPointer)->print_positions(); 
} 


void print_Atoms_pointer_positions(void * voidAtomsPointer) 
{ 
    //Cast the pointer as an atoms pointer 
    Atoms *atomsPointer = static_cast<Atoms *>(voidAtomsPointer); 

    atomsPointer->print_positions(); 
} 

int main() 
{ 
    //Use the initializer function for getting a pointer 
    void *testVoidAtomsPointer; 

    initialize_Atoms_void_pointer(&testVoidAtomsPointer); 
    print_Atoms_pointer_positions(testVoidAtomsPointer); 
} 
+2

En plus du tableau local qui est votre problème principal, un autre problème est que elemN n'est pas une expression de constante de temps de compilation, donc il est mal formé pour l'utiliser comme taille du tableau. C'est facile à corriger en ajoutant 'const'. – user2079303

+0

'new',' void * '. Même C++ 98 a 'std :: vector', et C++ 11 introduit' std :: shared_ptr <> '. Ce code souffre vraiment parce qu'il réinvente la roue, mal. – MSalters

+0

Merci pour cette suggestion. Malheureusement, dans ce problème, je suis quelque peu contraint d'utiliser les outils très basiques. –

Répondre

4

Le problème est que, dans

Atoms *atoms = new Atoms(numAtoms, data_array); 

data_array est un réseau local, qui est détruit lorsque initialize_Atoms_void_pointer quitte.

Au lieu de copier le pointeur brut, faire une nouvelle allocation dans le constructeur de Atoms et copier le contenu:

Atoms(int nAtoms, double * positionsArray) 
{ 
    this->nAtoms = nAtoms; 
    this->positions = new double[nAtoms]; 
    for (int ii = 0; ii < nAtoms; ++ii) 
    this->positions[ii] = positionsArray[ii]; 
} 

~Atoms() 
{ 
    delete[] this->positions; 
} 

Une plus sûre mise en œuvre comprendrait l'utilisation d'un std::unique_ptr, qui automatiquement désallouer la mémoire pour vous quand Atoms est détruit:

#include <memory> 

class Atoms { 
    std::unique_ptr<double[]> positions; 
    // ... 

public: 
    Atoms(int nAtoms, double * positionsArray) : 
    positions(new double[nAtoms]) { 
    this->nAtoms = nAtoms; 
    for (int ii = 0; ii < nAtoms; ++ii) 
     this->positions[ii] = positionsArray[ii];   
    } 

    // ... 
}; 

vous auriez besoin également vérifier si nAtoms est 0 ou négatif, si le tableau d'entrée est nulle, etc., mais je pense qu'il fal Est hors de la portée de la question.

Si vous avez besoin d'accéder au pointeur brut, vous pouvez utiliser la méthode positions.get() (n'essayez pas de le supprimer ou votre application va planter en raison d'une double suppression).

Mise à jour

Bien sûr, une autre solution plus simple est tout simplement d'utiliser un std::vector<double> à la place;)

#include <vector> 

class Atoms { 
    std::vector<double> positions; 
    // int nAtoms; -- no longer necessary 

public: 
    Atoms(int nAtoms, double * positionsArray) : 
    positions(nAtoms) { 
    for (int ii = 0; ii < nAtoms; ++ii) 
     this->positions[ii] = positionsArray[ii];  
    } 

    // ... 
}; 

Si vous avez besoin pour accéder au pointeur brut, vous pouvez utiliser la méthode positions.data() (n'essayez pas de le supprimer ou votre application va planter en raison d'une double suppression). Le nombre d'atomes peut être vérifié en utilisant positions.size().

Comme mentionné dans un commentaire, si le seul but de la classe Atoms est de stocker des doublons mais de ne pas ajouter d'autres opérations, il suffit de les oublier et d'utiliser directement le std::vector<double>.