更改继承成员的地址
Changing address of inherited members
我遇到了一个奇怪的问题,我想知道 C++11 是否有关于此的特殊规则我不知道。
我有 2 个 classes :
1 - ClNeuron(摘要)
2 - ClLSTMNeuron(ClNeuron 的child)
声明如下:
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 构造函数调用它的 parent class 函数 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
我们可以清楚地看到神经元本身的地址和成员m_output_connections的地址发生了变化:为什么会发生这种情况?
有没有继承/多态的概念不知道会不会?
我正在考虑典型的指针问题:索引不匹配、未初始化的指针等...
但似乎找不到任何会触发这种行为的东西。
问题在 Visual Studio 2015 和 GCC Linux 中是可复制的。
P.S
您可能会在这段代码中看到一些错误,因为它不遵循 non-written 规则,例如:
始终使用虚拟析构函数或类似概念。
请随时让我知道我可能犯的任何错误。
再次感谢您的宝贵时间!
如果我明白发生了什么事和你问什么,地址改变的原因是:
(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,它只是保留足够的内存来容纳 p_number_of_neurons 的 ClLSTMNeuron。
我不是 c++ 标准专家,但据我了解,这个过程类似于 new[] news up some memory。然后它调用 ClLSTMNeuron 的构造函数,该构造函数分配并初始化 ClLSTMNeuron 的内存和 returns 对该内存位置的 const 引用。然后将该内存移动到由 new.
分配的内存中
或更简单地说,构造函数设置一些内存,然后将其移入数组。所以这个的内存地址可能会变,也可能不会变。
同样,我不是专家,其他人可能会更恰当地解释它。如果您想做一些研究,请尝试阅读 c++ standard.
的第 5.3.4 节
如果你有:
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))
我遇到了一个奇怪的问题,我想知道 C++11 是否有关于此的特殊规则我不知道。
我有 2 个 classes :
1 - ClNeuron(摘要)
2 - ClLSTMNeuron(ClNeuron 的child)
声明如下:
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 构造函数调用它的 parent class 函数 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
我们可以清楚地看到神经元本身的地址和成员m_output_connections的地址发生了变化:为什么会发生这种情况? 有没有继承/多态的概念不知道会不会?
我正在考虑典型的指针问题:索引不匹配、未初始化的指针等... 但似乎找不到任何会触发这种行为的东西。
问题在 Visual Studio 2015 和 GCC Linux 中是可复制的。
P.S 您可能会在这段代码中看到一些错误,因为它不遵循 non-written 规则,例如: 始终使用虚拟析构函数或类似概念。 请随时让我知道我可能犯的任何错误。
再次感谢您的宝贵时间!
如果我明白发生了什么事和你问什么,地址改变的原因是:
(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,它只是保留足够的内存来容纳 p_number_of_neurons 的 ClLSTMNeuron。
我不是 c++ 标准专家,但据我了解,这个过程类似于 new[] news up some memory。然后它调用 ClLSTMNeuron 的构造函数,该构造函数分配并初始化 ClLSTMNeuron 的内存和 returns 对该内存位置的 const 引用。然后将该内存移动到由 new.
分配的内存中或更简单地说,构造函数设置一些内存,然后将其移入数组。所以这个的内存地址可能会变,也可能不会变。
同样,我不是专家,其他人可能会更恰当地解释它。如果您想做一些研究,请尝试阅读 c++ standard.
的第 5.3.4 节如果你有:
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))