Каков наиболее эффективный способ регулирования памяти при передаче массивов в качестве аргументов? - PullRequest
1 голос
/ 12 июля 2020

Я научился программировать на Python и только сейчас изучаю C ++, поэтому прошу прощения, если термины, которые я использую, не являются общепринятыми (также у меня нет научного образования или опыта).

Я пытаюсь построить нейрон на C ++. Веса обычно передаются в виде массивов. При создании экземпляров нейронов мне нужно передать массив весов. Я пытался заставить объект нейрона просто ссылаться на указатель, поэтому мне не нужно делать копию, но я продолжаю делать что-то не так. Может ли кто-нибудь изменить этот код, чтобы я не делал копию массива, а затем объяснял, что вы сделали, и почему вы это сделали?

class Neuron {
    private:
        double bias;
        int num_weights;
        double weights[];
    public:
        Neuron(double*, int, double);
        double forward_prop(double[]);
};

Neuron::Neuron(double weights[], int num_weights, double bias) {
    this->num_weights = num_weights;
    this->bias = bias;
    // rotate through weights pointer and reassign to object attribute 'weights'
    for (int i=0;i<this->num_weights;i++) {
        this->weights[i] = weights[i];
    }
    // TODO: delete pointer

}

double Neuron::forward_prop(double values[]) {
    double output = this->bias;

    for (int i=0; i < this->num_weights; i++) {
        output += this->weights[i] * values[i];
    }
    return output;

}

1 Ответ

5 голосов
/ 12 июля 2020

Вот перезапись вашего класса без копирования объекта и с использованием стандартной библиотеки C ++. В приведенном ниже примере используется std::vector вместе с семантикой перемещения, чтобы избежать копирования данных. Комментарии идут после образца кода:

#include <vector>
#include <numeric>
#include <iostream>

class Neuron 
{
    private:
        std::vector<double> weights;  // We use a vector of doubles, not an array
        double bias; 

    public:
    
        Neuron(std::vector<double>&, double);
        double forward_prop(const std::vector<double>&);
};

Neuron::Neuron(std::vector<double>& weights_, double bias_) : weights(std::move(weights_)), bias(bias_) // The std::move avoids the copy
{}

double Neuron::forward_prop(const std::vector<double>& values) 
{
    // the std::inner_product function does what your code is doing now
    return std::inner_product(weights.begin(), weights.end(), values.begin(), bias);
}

int main()
{
    std::vector<double> myWeights {1,2,3,4};
    Neuron n(myWeights, 10);
    std::cout << n.forward_prop({5,6,7,8});
}

Вывод:

80

Вот ключевые моменты:

  1. std::vector - это используется вместо массивов и указателей. Обратите внимание, что нам больше не нужна переменная-член num_weights, поскольку вектор уже знает свой размер, вызвав функцию-член size() для std::vector.

  2. в Neuron конструктор, мы вызываем std::move, когда присваиваем переданный вектор члену объекта. Это вызывает семантику перемещения, которая встроена в std::vector. Обычно указатели, которые использует исходный вектор, «украдены» или перемещены в целевой вектор, что позволяет избежать копирования.

Обратите внимание, что исходный вектор будет изменен когда это будет сделано . Переданный вектор станет по существу пустым (помните, что его содержимое было перемещено).

В довершение всего, я реализовал ваш forward_prop, используя std :: inner_product .

Дополнительные элементы - обратите внимание на использование список инициализации членов при написании конструкторов. Кроме того, при вызове forward_prop используется синтаксис инициализации скобок std::vector, поэтому, когда мы вызывали forward_prop, не было необходимости явно объявлять std::vector<double>.

Заметьте, что реальный момент, который нужно вывести из этого, заключается в том, что, начиная с C ++ 11, семантика перемещения была формально введена в язык. Это позволяет выполнять перемещение (вместо копирования) формальным образом.

Теперь, когда возможна семантика перемещения, были добавлены дополнительные функции (такие как std::move, конструкторы перемещения и операторы присваивания перемещения, emplace_back функции-члены в некоторых классах контейнеров STL, std::unique_ptr работает вместо несколько сломанных std::auto_ptr, и c.).

До C ++ 11 вам приходилось использовать "трюки" с указателями или надеюсь, что оптимизатор компилятора неявно переместил (хотя формального названия для этого типа операции не было).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...