0

私は最初の場所にポインタを渡すことによって配列が関数に渡されるコードに取り組んでいます。この関数では、配列の一部が使用されます。これは、呼び出し元関数が配列の最大サイズを正しく推測しない場合、呼び出し先関数が配列サイズを超えて正しく書き込むことができ、スタックオーバーフローが発生する可能性があるため、安全ではない状況になります。私はこれに対する解決策を考えており、この例に示すように、関数テンプレートを使用し、配列を参照として渡すことを考えました。配列をC++の関数に渡すときにスタックオーバーフローを避けるには?

modifyArray.h

#define MAXSIZE 10 

class modifyArray 
{  
public: 
    void create(); 

    void unsafeFunction(double*); 

    template<int N> 
    void safeFunction(double (&array)[N]); 

private: 
    int computeLength(); 
}; 

私が探していますmodifyArray.cpp

#include <iostream> 
#include "modifyArray.h" 

int modifyArray::computeLength() 
{ 
    return 11; 
} 

void modifyArray::create() 
{ 
    double testarray[MAXSIZE]; 
    unsafeFunction(testarray);  
    safeFunction(testarray); 
} 

void modifyArray::unsafeFunction(double* array) 
{ 
    int operatingSize = computeLength(); 
    for(int i = 0; i < operatingSize; i++) { 
     array[i] = i*i; 
    } 
} 

template<int N> 
void modifyArray::safeFunction(double (&array)[N]) 
{ 
    int operatingSize = computeLength(); 
    std::cout<< "Max size" << N <<std::endl; 
    if(operatingSize > N) return; // Return or raise an exception 

    for(int i = 0; i < operatingSize; i++) { 
     array[i] = i*i; 
    } 
} 

main.cppに

#include "modifyArray.h"  

int main(int argc, const char * argv[]) {  
    modifyArray C;  
    C.create(); 
    return 0; 
} 

既存のコードを最小限に抑えるソリューションです。ここでは、テンプレートステートメントを追加し、引数をdoubleからreferenceに変更して、ifステートメントを挿入してサイズを確認するだけです。私は大きな書き換えをしたくありません。また、私は動的な割り当て、ベクトル、またはstd :: arrayを使用したくないのはパフォーマンスの理由からです。これは数値シミュレーションコードの低レベル関数であり、パフォーマンスは非常に重要です。より良い解決策はありますか?私がやっていることに落とし穴はありますか?

+4

* [...]または主な原因パフォーマンス上の理由のSTD ::配列*:あなたは

int main() { int arr[10]; do_work(arr, []() { static int i = 0; i++; return i * i; }); for (auto e : arr) std::cout << e << " "; } 

出力のようにそれを使用することができます。 'std :: array'は配列の単なるラッパーであり、生の配列と同じ実行時のパフォーマンスを持ちます。 – NathanOliver

+2

要素の数を示す別のパラメータを渡すか、単に 'std :: array'を使用してください。パフォーマンスは同じになります。 –

+1

また、私はあなたがスタックのオーバーフローを記述しているとは思わない。境界外の例外を記述しています。 –

答えて

4

生の配列を実際に使用したい場合、配列のすべての要素を最後まで歩かずに安全に変更するには、配列を参照渡ししてからrange based for loopを使用します。

tmeplate <typename T, typename Function, std::size_t N> 
void do_work(T (&arr)[N], Function f) 
{ 
    for (auto & e : arr) 
     e = f(); 
} 

上記は、関数のすべての要素にfunctionを呼び出した結果を適用し、配列の境界内にとどまることが保証されています。

1 4 9 16 25 36 49 64 81 100 

Live Example

+0

アイデアありがとうございました。あなたの例では、 'do_work'のループは常に' arr'の完全な長さになります。私の実際のコードでは、 'do_work'を同じ配列で複数回呼び出すが、毎回異なる長さの配列を使用したい。しかし、アイデアをありがとう。また 'safeFunction'と' unsafeFunction'と 'computeLength'は単なる例ですが、私の実際のコードはもっと複雑なことをします。 – user3469604

+0

@ user3469604もし私たちがこの場合、あなたは 'N 'に対して' N'に対してどのくらい走りたいかをいつでも比較することができます。 'N'は配列のサイズになります。 – NathanOliver

関連する問題