【问题标题】:What is the most efficient way of regulating memory when passing arrays as arguments?将数组作为参数传递时调节内存的最有效方法是什么?
【发布时间】:2020-11-02 01:01:11
【问题描述】:

我学习了 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;

}

【问题讨论】:

  • 在你的课堂上double weights[]; 不是合法的 C++。
  • 如果您想避免复制“数组”(实际上是一个指针),那么只需复制指针this-&gt;weights = weights;。这是否是一个好主意是有争议的(至少可以说),但你会这样做。
  • 您也不需要在几乎所有使用它的地方指定this-&gt;。 -- 我学会了用 Python 编程 -- 一个警告:不要使用 Python(或任何其他语言)作为编写适当 C++ 代码的模型。
  • 我一直试图让神经元对象只引用指针,这样我就不必复制了 -- 那么哪个实体拥有指针?是Neuron 对象,还是调用者?
  • 我认为你仍然应该坚持编写高级代码,但使用现代技术(例如,移动语义,使用具有良好缓存局部性的数据结构等)。如果存在性能问题(在使用分析器测量之后),则考虑使用指针的低级技术。

标签: c++ arrays pointers neural-network instantiation


【解决方案1】:

这是您的类的重写,没有对象复制,并使用 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 成员变量,因为通过调用std::vectorsize() 成员函数,向量已经知道自己的大小。

  2. Neuron 构造函数中,当我们将传入的向量分配给对象的成员时,我们会调用std::move。这会调用std::vector 中内置的移动语义。基本上,源向量使用的指针被“窃取”或移动到目标向量中,从而避免了复制。

请注意,完成此操作后,源向量将被更改。传入的向量本质上将变为空(请记住,它的内容已被移出)。

  1. 最重要的是,我使用std::inner_product 实现了您的forward_prop

  2. 附加项——在编写构造函数时注意成员初始化列表的使用。另外,对forward_prop 的调用使用std::vector 的大括号初始化语法,这就是为什么当我们调用forward_prop 时,不需要显式声明std::vector&lt;double&gt;


请注意,真正要摆脱的一点是,从 C++11 开始,移动语义被正式引入该语言。这允许以正式的方式进行移动(而不是复制)。

现在可以使用移动语义,添加了其他功能(例如std::move、移动构造函数和移动赋值运算符、某些 STL 容器类中的emplace_back 成员函数、std::unique_ptr 可以代替有些损坏的@ 987654341@等)。

在 C++11 之前,您必须使用指针“技巧”或希望编译器的优化器隐式进行移动(即使此类操作没有正式名称)。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2018-06-09
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多