2017-04-26 19 views
2

クラスオブジェクトへのvoidポインタを作成し、関数内で初期化しようとしています。残念ながら、クラスの配列メンバは関数をエスケープできません。つまり、初期化後にアクセスすることはできません。クラスオブジェクトへのポインタ無効化:関数内の初期化

以下のコードでは、初期化関数内の最初の呼び出し(initialize関数内)は正常に動作しますが、初期化関数外の印刷位置への2回目の呼び出しは失敗します。私は、初期化関数で作成された配列オブジェクトが破棄され、渡されていないと感じていますが、わかりませんし、修正方法もわかりません。

ご協力いただければ幸いです。

#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

あなたの中心的な問題である配列のほかに、もう1つの問題は、 'elemN'はコンパイル時定数式ではないため、配列のサイズとして使用するのは不適切です。これは 'const'を加えることで簡単に修正できます。 – user2079303

+0

'new'、' void * ' C++ 98でも 'std :: vector'があり、C++ 11は' std :: shared_ptr <> 'を導入しました。このコードは実際には苦しんでいます。なぜなら、ホイールを再開発しているからです。 – MSalters

+0

この提案をありがとうございます。残念ながら、この問題では、非常に基本的なツールのみを使用するように私は幾分制約されています。 –

答えて

4

問題が

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

data_arrayinitialize_Atoms_void_pointerが終了します破壊されるローカル配列、ということです。

代わりの生のポインタをコピーし、Atomsさんにコンストラクタを新しい割り当てを作成し、コンテンツをコピーします。

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

より安全な実装が自動的れる割り当て解除、std::unique_ptrの使用が含まれますAtomsが破壊されたあなたのためのメモリ:

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

    // ... 
}; 

あなたが入力配列等、nullの場合nAtomsは、0または負であるかどうかを確認することも必要だろうが、私はFALそれを考えます問題の範囲外です

生ポインタにアクセスする必要がある場合は、positions.get()メソッドを使用することができます(削除しようとしないでください。アプリケーションが2回削除されてクラッシュする可能性があります)。

更新

もちろん、他のより簡単な解決策ではなくstd::vector<double>を使用するだけである。)

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

    // ... 
}; 

あなたは生のポインタにアクセスする必要がある場合は、positions.data()メソッドを使用することができます(それを削除しようとしないでください。そうしないと、アプリケーションは二重削除のためにクラッシュします)。原子数はpositions.size()で確認できます。

Atomsクラスの唯一の目的は、倍精度を格納することですが、他の操作を追加することではない場合は、それを忘れて直接std::vector<double>を使用してください。

関連する問題