对象向量的分割错误

Segmentation fault on vector of objects

本文关键字:错误 分割 向量 对象      更新时间:2023-10-16

我目前正在尝试编程一个神经网络头文件来训练神经网络,NN.h文件包含了所有的神经网络内容。NN.h还包括我自己编程的另一个头文件,名为Matrix.h,其中包含一个类,用于处理所有矩阵内容和内存管理。

当我不为Matrix对象使用向量时,内存管理工作得很好,但一旦我将它们与向量一起使用,就会出现Segmentation错误。

这是程序输出:

Matrix destruction started
0 0 0 
Matrix destruction started
0 0 0 
Matrix destruction started
0 0 0 
0 0 0 
0 0 0 
Matrix destruction started
2 2 2 
Matrix destruction started
10 10 10 
Matrix destruction started
9 
Segmentation fault (core dumped)

NN.h:

#include <vector>
#include <string>
#include <stdlib.h>
#include "matrix.h"
#include <time.h>
#include <string>
class NN{
private:
std::vector<int> info;
std::vector<Matrix<double> > layer;
std::vector<Matrix<double> > weights;
std::vector<Matrix<double> > bias;
std::vector<Matrix<double> > result;
std::vector<Matrix<double> > temp;
double learnigRate;
public:
NN(std::vector<int> &layers){
info = layers;
layer.reserve(layers.size());
for (size_t i = 0;i < layers.size();i++){
layer.push_back(Matrix<double> (layers[i],1,0));
}
weights.reserve(layers.size()-1);
for (size_t i = 0;i < (layers.size()-1);i++){
weights.push_back(Matrix<double> (layers[i],layers[i+1],0));
}
bias.reserve(layer.size()-1);
for (size_t i= 0; i < (layers.size()-1);i++){
bias.push_back(Matrix<double> (layers[i+1],1,2));
}
result.push_back(Matrix<double> (layers[layers.size()-1],1,10));
temp.push_back(Matrix<double> (1,1,9));
}
~NN(){
for (size_t i = 0;i < info.size();i++){
delete &layer[i];
}
for (size_t i = 0;i < (info.size()-1);i++){
delete &weights[i];
}
for (size_t i= 0; i < (info.size()-1);i++){
delete &bias[i];
}
delete &result[0];
delete &temp[0];
}
};

矩阵.h:

#include <stdio.h>
#include <iostream>
#include <exception>
template <class W> class Matrix{
private:
int state = 0;
int printError(Matrix<W> &a){
if(state != 0 && a.state != 0){
std::cerr <<"matrix.h error : " << "Both matrices not correctly initialized!" << std::endl;
return 1;
}
if(state != 0){
std::cerr <<"matrix.h error : " << "Matrix 1 not correctly initialized!" << std::endl;
return 1;
}
if(a.state != 0){
std::cerr <<"matrix.h error : " << "Matrix 2 not correctly initialized!" << std::endl;
return 1;
}
return 0;
}
public:
W ** matrix;
int size_x,size_y;
template <typename X> Matrix(int size_tx,int size_ty,X value){
W temp = (W) value;
size_x = size_tx;
size_y = size_ty;
int x = 0;
try{
matrix = new W*[size_y];
}
catch(const std::bad_alloc&)
{
std::cerr << "Could not allocate matrix: bad_alloc()" << std::endl;
state = 1;
return;
}
try{
for(x = 0; x < size_y;x++){
matrix[x] = new W[size_x];
}
}
catch (const std::bad_alloc&)
{
std::cerr << "Could not allocate matrix: bad_alloc()" << std::endl;
for(int i = 0; i < x-1;i++){
delete [] matrix[i];
}
state = 1;
return;
}
for(int i = 0; i < size_y; i++){
for(int j = 0;j< size_x;j++){
matrix[i][j] = temp;
}
}
state = 0;
}
~Matrix(){
if (state == 0)
freeMatrix();
}
int freeMatrix(){
std::cout << "Matrix destruction started" << std::endl;
printMatrix();
for(int i = 0; i < size_y;i++){
delete [] matrix[i];
}
delete [] matrix;
return 0;
}
int printMatrix(){
for(int i = 0; i < size_y; i++){
for(int j = 0;j< size_x;j++){
std::cout << matrix[i][j] << " ";
}
printf("n");
}
return 0;
}
};

main.cpp:

#include <iostream>
#include <vector>
#include "matrix.h"
#include "NN.h"
using namespace std;
int main(){
vector<int> net (3);
net = {3,3};
NN n(net);
return 0;
}

这些是我代码的缩短版本,但相关部分应该仍然存在。

当我删除NN类的析构函数时仍然存在相同的错误,然而,当我删除矩阵析构函数时,没有错误,但我想用一个尊重内存管理的干净解决方案来解决这个问题。

如果你需要更多信息,请随时询问我。

显然,~NN()的实现是错误的。删除未动态分配的对象是没有意义的。添加项目时,对象(堆栈上)会被推回。

既然在NN中使用向量,为什么不在Matrix中也这样做呢?它将大大简化代码,有助于防止内存泄漏,并使代码更强大、更安全。。。

在构造函数中捕获异常并设置一个标志来指示失败是一个非常糟糕的主意事实上,在语言中添加了异常是为了避免这种模式众所周知,这是近20年来的不良做法。。。

另一件事是,您在没有定义复制构造函数(也没有定义赋值运算符)的情况下复制Matrix对象,并且假设您使用的是C++11,您还应该提供移动构造函数和赋值。

您应该做的另一件事是始终将匹配的头文件放在给定源的包含列表的第一位(如果适用,则仅在预编译头之后)。这样,它有助于确保任何头文件都可以自行编译。

我建议你读一些关于C++的好书,比如卓越的C++。网上也有很多可用的信息。例如,你应该学习5等规则(例如:http://www.cppsamples.com/common-tasks/rule-of-five.html或http://en.cppreference.com/w/cpp/language/rule_of_three)。

在现代C++中,建议避免显式内存管理。您应该使用诸如std::vector、std::unique_ptr,std::shared_ptr等类来帮助您编写可维护的异常安全代码。

如果你想学习C++,那么你必须在学习上下很大的功夫。否则,切换到更简单的语言,如C#或Swift。。。