对象向量的分段错误

Posted

技术标签:

【中文标题】对象向量的分段错误【英文标题】:Segmentation fault on vector of objects 【发布时间】:2017-10-31 22:36:27 【问题描述】:

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

当我不将向量用于 Matrix 对象时,内存管理工作正常,但一旦我将它们与向量一起使用,我就会收到分段错误错误。

这是程序输出:

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类的析构函数还是出现同样的错误, 但是,当我删除 Matrix 析构函数时没有错误,但我想用一个尊重内存管理的干净解决方案来解决这个问题。

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

【问题讨论】:

当您在调试器中运行它时,它到达了哪里? 我已经用gdb单步执行了代码,在freeMatrix()delete [] matrix[i];处出现分段错误 当我删除 NN 析构函数时,出现双重释放或损坏错误,而不是分段错误! 显然,它在那里失败了,因为您不应该在该对象上调用 delete,因为它没有在堆上分配(即 new 未用于创建该对象)。 好的,但是当我删除 NN 析构函数时仍然出现分段错误 【参考方案1】:

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

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

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

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

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

我建议您阅读有关 C++ 的好书,例如 Exceptional 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...

【讨论】:

以上是关于对象向量的分段错误的主要内容,如果未能解决你的问题,请参考以下文章

推送到成员向量时的段错误

在 C++ 中使用向量时出现分段错误

向量:: 擦除分段错误

带有向量和字符串的 C++ 分段错误

在 C++ 中使用向量的分段错误?

C ++中向量中的分段错误