2016-09-01 2 views
0

C++ 객체 자체에 대한 참조를 반환하는 메서드가있을 수 있습니까? 개체의 클래스의 여러 독립 인스턴스를 원합니다.C++ 클래스 자체에 대한 참조 반환

다차원 배열의 연산자 []을 구현하기위한 것입니다. 나는 Array[0][1][2]과 같은 것을 원한다.

감사합니다.

업데이트 : 다차원 배열

구현 :

사용 목적 :

A[0][1] = 4; //the element at 0th row and 1st column is now 4. 
A[0] = 5;  //all elements of the 0th row are now 5. 
A["all"][1] = 10; //all elements of the 1st column are now 10; 

대상물 (A)이 정확한지 SIMD 정렬과 메모리 청크 포인터 ptr_buffer있다. A의 생성자는 메모리를 할당합니다. A의 소멸자가 메모리 할당을 해제합니다. A []는 객체 B를 반환합니다.

객체 B는 포인터 A의 메모리 하위 섹션에 ptr_A_buffer을 가지고 B []는 ptr_A_buffer을 수정하고 자체에 대한 참조를 반환합니다. 나는 각각의 [] 연산에 대해 객체 B를 끊임없이 만들고 싶지 않다.

A와 B는 모두 동일한 추상 클래스에 속합니다. 수학 함수는 추상 클래스를 인수로 사용합니다.

+0

있음이 가능하다 .. – Rakete1111

+1

항상 일어나는'연산자의 일반적인 형태가 = '객체 자체에 대한 참조를 반환한다. –

+0

어떻게 할 수 있습니까? – rxu

답변

1

나는이 아이디어에 대해 궁금해했다. 청구서에 맞는 데이터 유형이 있습니다. 차원에 대해 3 개의 정수로 호출되면 연속적인 메모리를 할당 한 다음 사용자가 더 작은 차원 (평면, 행, 단일 값)을 갖는 데이터에 "뷰"를 정의 할 수있게하는 배열 유형입니다.

이전에 실제로 사용하지 않은 공유 포인터를 사용했기 때문에 실수를했을 수도 있습니다. 나는 교정을 환영한다.

아이디어는 주변의보기를 복사하는 것이 얕습니다. 그들은 모두 동일한 기본 데이터에서 작동합니다. 이렇게하면 합리적인 효율성으로 믿을 수있는 가치로 전달할 수 있습니다.

#include <iostream> 
#include <iomanip> 
#include <memory> 

using namespace std; 

/// This class is a three-dimensional array of doubles. 
/// It defines an index operator which returns a view into that 
/// data that is of one lesser dimension, just like the standard 
/// index operator on plain old arrays. The last index operation 
/// yields an "array" which is a single value. 
/// Converting to double and assigning from double is defined as 
/// using the first double in the view. 
class NDimArrT 
{ 
    /// All slices hold a shared pointer to the base data they 
    /// are looking into so that their view stays valid. 
    const shared_ptr<double> baseData; 

    /// The data the view is looking at. Identical to the shared 
    /// ptr for the original object. 
    double *const slice; 

    /// The three dimensions, in the order of indexing. 
    /// All three of them may be zero, indicating a single value. 
    const int dim1, dim2, dim3; 

public: 

    /// A single double value view into a one-dimensional array 
    NDimArrT(const shared_ptr<double> base, double *sliceStart) 
     : baseData(base), slice(sliceStart), dim1(0), dim2(0), dim3(0) {} 

    /// A 1D vector/row view into a two-dimensional array. 
    /// @param dim1Arg is the length of the row. 
    NDimArrT(const shared_ptr<double> base, double *sliceStart, int dim1Arg) 
     : baseData(base), slice(sliceStart), dim1(dim1Arg), dim2(0), dim3(0) {} 

    /// A 2D matrix plane view into the cube 
    NDimArrT(const shared_ptr<double> base, double *sliceStart, int dim1Arg, int dim2Arg) 
     : baseData(base), slice(sliceStart), dim1(dim1Arg), dim2(dim2Arg), dim3(0) {} 

    /// A 3D cube. This actually allocates memory. 
    NDimArrT(int dim1Arg, int dim2Arg, int dim3Arg) 
     : baseData(new double[dim1Arg*dim2Arg*dim3Arg], std::default_delete<double[]>()), 
      slice(baseData.get()), // the data view is the whole array 
      dim1(dim1Arg), dim2(dim2Arg), dim3(dim3Arg) {} 

    /// Perform a shallow copy. We assume that e.g. returning a slice means 
    /// essentially returning another view into the main base array. 
    NDimArrT(const NDimArrT &rhs) = default; 

    /// Use standard move semantics. The rhs will be invalidated, and the 
    /// reference count to the base array does not grow. Can be used to return results from 
    /// functions. 
    NDimArrT(NDimArrT &&rhs) = default; 

    /// Default destructor; destroy baseData if it's the last reference. 
    ~NDimArrT() = default; 

    /// Get the value of the first element we look at. Handy for 
    /// single value views. 
    operator double() const { return *slice; } 

    /// Return an instance of NDimArrT representing a view 
    /// with one dimension less than this. If we have a single value 
    /// already, simply return this single value. (We should 
    /// perhaps throw an exception there.) 
    NDimArrT operator[](int ind) 
    { 
     // This could be regarded an error, because this view 
     // is already a single element. 
     if(GetDims() == 0) { return *this; } 

     // This view is a 1-dimensional vector. Return the element at ind. 
     if(dim2==0) { return NDimArrT(baseData, slice + ind); } // return a single value. 

     // This view is a 2D matrix. Return the row no. ind. 
     // The row length is dim2. (Dim 1 indicates how many rows.) 
     if(dim3==0) { return NDimArrT(baseData, slice + dim2*ind, dim2); } // return a 1D vector 

     // This view is a true 3D cube matrix. dim1 is the number of planes, 
     // dim2 is the number of rows in a plane, dim3 is the length of each row. 
     // Return the plane no. ind, which starts at ind*planesize, i.e. ind*dim2*dim3. 
     // The number of rows and row length are dim2 and dim3, respectively. 
     return NDimArrT(baseData, slice + dim2*dim3*ind, dim2, dim3); // return a 2D matrix. 
    } 

    NDimArrT &operator=(double d) { *slice = d; } 

    int Len() { return dim1 ? dim1 : 1; } // interestingly, length is always dim1. 

    int GetDims() const 
    { 
     return dim1 
       ? dim2 
        ? dim3 
         ? 3 
         : 2 
        : 1 
       : 0; 
    } 

}; 

/// An example function which initializes an NDimArr of unknown 
/// dimensionality with nice numbers.. 
void initNDimArr(NDimArrT arr, int &startVal) 
{ 
    // Single value? Give it the start value and increment that. 
    if(arr.GetDims() == 0) { arr = startVal++; } 
    else 
    { 
     for(int ind=0; ind<arr.Len(); ind++) { initNDimArr(arr[ind], startVal); } 
    } 
} 

// An example function doing something with 
// an unknown n-dimensional array 
void printNdimArr(NDimArrT nDimArr) 
{ 
    if(nDimArr.GetDims() == 0) { cout << setw(4) << nDimArr << " "; } 
    else 
    { 
     for(int i=0; i<nDimArr.Len(); i++) { printNdimArr(nDimArr[i]); } 
     cout << endl; 
    } 
} 
int main() 
{ 
    NDimArrT arr(3,4,5); 
    int start = 1; 
    initNDimArr(arr, start); 
    printNdimArr(arr); 

    // now use the middle plane of the 3 4x5 planes 
    cout << "Middle plane, values starting at 100:" << endl; 
    auto middlePlane = arr[1]; 
    start = 100; 
    initNDimArr(middlePlane, start); 
    printNdimArr(middlePlane); 

    cout << "Whole array now:" << endl; 
    printNdimArr(arr); 

    cout << "Print line 2 of the 3rd plane:" << endl; 
    printNdimArr(arr[2][1]); 

    cout << endl << "Last number in that row is " << arr[2][1][4] << endl; 
} 

샘플 세션 :

$>g++ -std=c++11 -o ndimContiguousArr ndimContiguousArr.cpp && ./ndimContiguousArr 
    1 2 3 4 5 
    6 7 8 9 10 
    11 12 13 14 15 
    16 17 18 19 20 

    21 22 23 24 25 
    26 27 28 29 30 
    31 32 33 34 35 
    36 37 38 39 40 

    41 42 43 44 45 
    46 47 48 49 50 
    51 52 53 54 55 
    56 57 58 59 60 


Middle plane, values starting at 100: 
100 101 102 103 104 
105 106 107 108 109 
110 111 112 113 114 
115 116 117 118 119 

Whole array now: 
    1 2 3 4 5 
    6 7 8 9 10 
    11 12 13 14 15 
    16 17 18 19 20 

100 101 102 103 104 
105 106 107 108 109 
110 111 112 113 114 
115 116 117 118 119 

    41 42 43 44 45 
    46 47 48 49 50 
    51 52 53 54 55 
    56 57 58 59 60 


Print line 2 of the 3rd plane: 
    46 47 48 49 50 

Last number in that row is 50 
+0

나는 shared_pointer가 존재한다는 것을 결코 알지 못했습니다. 코드를 주셔서 대단히 감사합니다. – rxu

+0

스마트 포인터를 사용하는 방법을 배우고 나면 인터넷에서 스마트 포인터 복사가 느리다는 것을 알게됩니다. 배열 된 배열 객체의 메모리를 보는 정렬 된 배열 클래스와 NDArray 객체를 만들 것입니다. 스마트 포인터는 피할 수 있지만 다른 문제가 있습니다. – rxu

+0

아. 디버그 플래그를 만들 수 있습니다. 디버그 플래그가 켜져 있으면 참조 카운팅을 수행합니다. 플래그가 꺼져 있으면 꺼지지 않습니다. 그것은 빠르고 안전합니다. – rxu