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 * в ссылку и вставить оператор if для проверки размера. Я не хочу делать серьезную переписку. Также я не хочу использовать динамическое распределение, вектор или std :: array в основном из-за причин производительности. Это низкоуровневая функция в коде численного моделирования, и производительность очень важна. Есть ли лучшее решение? Есть ли ловушка для того, чтобы делать то, что я делаю?

+4

* [...] или станд :: массив в основном из соображений производительности *. «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(); 
} 

выше будет применяться результат вызова функции для каждого элемента массива и гарантированно оставаться в пределах массива. Вы можете использовать его как

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

выход:

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' будет размером массива. – NathanOliver

Смежные вопросы