更改继承成员的地址

时间:2017-03-16 18:44:28

标签: c++ c++11 inheritance polymorphism memory-address


我有一个奇怪的问题,我想知道 C ++ 11 是否有关于此的特殊规则,我不知道。

我有两节课:

1 - ClNeuron (摘要)
2 - ClLSTMNeuron ClNeuron的孩子

声明如下:

class ClNeuron
{
    protected:

    //Initialization function
    virtual void Init(unsigned long p_uid);

    double Sigmoid(double p_value);
    double SigmoidDerivative(double p_value);

    double TanH(double p_value);
    double TanHDerivative(double p_value);

    public:

    const double CONST_DEFAULT_MOMENTUM_VALUE = 0.1;
    const double CONST_DEFAULT_LEARNING_RATE = 0.05;

    //All of the output connection of this neuron 
    std::vector<ClNeuronConnection*> m_output_connections;

    //Al of the input connection of this neuron
    std::vector<ClNeuronConnection*> m_input_connections;

    bool m_initialized;
    double m_result_buffer;

    //Error related informations
    double m_last_error_delta;  
    double m_error_gradient;

    unsigned long m_uid;
    double m_learning_rate;     

    public:

    bool m_is_bias;
    ClDataSet* m_dataset;

    virtual ~ClNeuron();
    ClNeuron(unsigned long p_uid);
    ClNeuron();


    //Connect this neuron's output to another / others neurons' input
    virtual bool AddOutputConnection(ClNeuron* p_neuron);

    //This neuron got a request to have multiple new input
    virtual std::vector<ClNeuronConnection*> InputConnectionRequest(ClNeuron* p_neuron);

    //Tell the neuron to fire the sum of the processed inputs
    virtual double Fire();
    virtual double Fire(double p_data);

    //void ComputeErrorGradient(double p_wanted_output);

    //Function updating all of the current neuron's weight of the OUTPUT connections , depending on an error ratio
    //void UpdateWeights();

    //Set the result buffer using the transfer function . NOTE : This is a pure virtual function
    virtual void ProcessInputs() = 0; 
    virtual bool ComputeErrorGradient() = 0;
    virtual void ComputeWeightDeltas();
    virtual void UpdateWeights();
    virtual void ResetContext();

    //Print neuron & connections & weights
    virtual void PrintNeuronData();
};



class ClLSTMNeuron : public ClNeuron
{
    protected:
    std::vector<ClNeuronConnection*> m_forget_gate_input_connections;
    std::vector<ClNeuronConnection*> m_input_gate_input_connections;
    std::vector<ClNeuronConnection*> m_output_gate_input_connections;
    double m_input_gate_result_buffer;
    double m_output_gate_result_buffer;
    double m_forget_gate_result_buffer;
    double m_cell_state;

    public:
    //Override the ProcessInputs function
    std::vector<ClNeuronConnection*> InputConnectionRequest(ClNeuron* p_neuron);
    void ProcessInputs();
    bool ComputeErrorGradient();
    ClLSTMNeuron();
    virtual ~ClLSTMNeuron();
};

问题如下: ClLSTMNeuron 构造函数调用它的父类函数 Init(),如下所示:

ClLSTMNeuron::ClLSTMNeuron()
{
    ClNeuron::Init(0);
    std::cout << "ClLSTMNeuron::ClLSTMNeuron() [" << this << "]: my OC [" << &this->m_output_connections << "] has a size of " << this->m_output_connections.size() << std::endl;
}

完成后,会给我以下输出:

ClLSTMNeuron::ClLSTMNeuron() [0000024BBC5720B8]: my OC [0000024BBC5720D0] has a size of 0
ClLSTMNeuron::ClLSTMNeuron() [0000024BBC5721D0]: my OC [0000024BBC5721E8] has a size of 0
ClLSTMNeuron::ClLSTMNeuron() [0000024BBC5722E8]: my OC [0000024BBC572300] has a size of 0
ClLSTMNeuron::ClLSTMNeuron() [0000024BBC572400]: my OC [0000024BBC572418] has a size of 0
ClLSTMNeuron::ClLSTMNeuron() [0000024BBC572518]: my OC [0000024BBC572530] has a size of 0
ClLSTMNeuron::ClLSTMNeuron() [0000024BBC572630]: my OC [0000024BBC572648] has a size of 0
ClLSTMNeuron::ClLSTMNeuron() [0000024BBC572748]: my OC [0000024BBC572760] has a size of 0
ClLSTMNeuron::ClLSTMNeuron() [0000024BBC572860]: my OC [0000024BBC572878] has a size of 0

在此输出中,我们可以清楚地看到每个 ClLSTMNeuron 实例的成员 m_output_connections 的地址。
但是,由于一个未知的原因,当我使用这样的动态分配实例化时:

this->m_neurons = new ClLSTMNeuron[p_number_of_neurons]();
if (this->m_neurons == NULL)
{
    std::cout << "[Fatal Error] ClLSTMNeuronLayer::Init : Impossible to allocate " << p_number_of_neurons << " neurons in memory" << std::endl;
    return false;
}


for (size_t i = 0; i < p_number_of_neurons; i++)
{
    std::cout << "LSTM Neuron " << i << " is at [" << &this->m_neurons[i] << "] and it's OC [" << &this->m_neurons[i].m_output_connections << "] has size of " << this->m_neurons[i].m_output_connections.size() << std::endl;
}

我得到以下输出:

LSTM Neuron 0 is at [0000024BBC5720B8] and it's OC [0000024BBC5720D0] h size of 0
LSTM Neuron 1 is at [0000024BBC572150] and it's OC [0000024BBC572168] h size of 18446743758171348710
LSTM Neuron 2 is at [0000024BBC5721E8] and it's OC [0000024BBC572200] h size of 18446743758171348500
LSTM Neuron 3 is at [0000024BBC572280] and it's OC [0000024BBC572298] h size of 315538203026
LSTM Neuron 4 is at [0000024BBC572318] and it's OC [0000024BBC572330] h size of 17994617993471572384
LSTM Neuron 5 is at [0000024BBC5723B0] and it's OC [0000024BBC5723C8] h size of 0
LSTM Neuron 6 is at [0000024BBC572448] and it's OC [0000024BBC572460] h size of 17994617993471572409
LSTM Neuron 7 is at [0000024BBC5724E0] and it's OC [0000024BBC5724F8] h size of 0   

我们可以清楚地看到神经元本身的地址&amp;成员 m_output_connections 的地址已更改:为什么会发生这种情况? 继承/多态中是否有任何概念,并且不知道?

我正在考虑典型的指针问题:索引不匹配,非初始化指针等... 但似乎找不到任何会引发这种行为的事情。

问题在Visual Studio 2015和GCC Linux中是不可复制的。

P.S 您可能会在此代码中看到错误,因为它不遵循非书面规则,例如: 始终使用虚拟析构函数或类似概念。 请随意让我知道我可能做的任何错误。

再次感谢您的时间!

2 个答案:

答案 0 :(得分:0)

如果你有:

ClNeuron* m_neurons

一旦你重复它就会出现问题:

this->m_neurons = new ClLSTMNeuron[p_number_of_neurons]();

因为指针算术将考虑ClNeuron而不是ClLSTMNeuron进行偏移计算。

所以m_neurons[n]

*static_cast<ClNeuron*>(static_cast<char*>(m_neurons) + n * sizeof(ClNeuron))

而不是预期

*static_cast<ClLSTMNeuron*>(static_cast<char*>(m_neurons) + n * sizeof(ClLSTMNeuron))

答案 1 :(得分:-1)

如果我理解发生了什么以及你在问什么,地址改变的原因是:

(14.3) — new T[5] results in a call of operator new[](sizeof(T)*5+x)

其中x是数组初始化开销

因此new ClLSTMNeuron[p_number_of_neurons]();不会在内存中的连续区域中生成p_number_of_neurons,它只是保留足够的内存来保存ClLSTMNeuron的p_number_of_neurons。

我不是c ++标准专家,但就我所知,这个过程就像新的[]新闻一样。然后它调用ClLSTMNeuron的构造函数,该构造函数分配并初始化ClLSTMNeuron值的内存并返回对该内存位置的const引用。然后将该内存移动到新的内存中。

或更简单地说,构造函数设置了一些内存,然后将其移入数组。所以这个的内存地址可能会也可能不会改变。

再次,我不是专家,其他人可以更正确地解释它。如果您想进行一些研究,请尝试阅读c ++ standard的第5.3.4节。