构造函数中的分段错误不明确

Unclear segmentation fault in a constructor

本文关键字:错误 不明确 分段 构造函数      更新时间:2023-10-16

我为矩阵对象构建了一个构造函数。数据存储在结构体val的数组中,该数组依次保存(矩阵中(位置和值。这是代码:

SparseMatrix::SparseMatrix(const int numRow, const int numCol, vector<double> fill):
        Matrix(numRow,numCol)
{
    _matrix = new vector<val*>(fill.size());
    vector<double>::iterator itr = fill.begin();
    for(signed int i=0; i<numRow; i++)
    {
        for(signed int j=0; j<numCol; j++, itr++)
        {
            if (*itr == 0)
            {
                continue;
            }
            val *temp = new val;
            temp->value = *itr;
            temp->x = i;
            temp->y = j;
            _matrix->push_back(temp);
            cout << "Psition: " << ": " << _matrix->front()->x << //<--ERROR     
            cout << " " << _matrix->back()->y << endl;
        }
    }
}

您会注意到,我添加cout只是为了验证push_back是否真的适用于我。_matrix在堆上,所有保存在堆中的结构也是如此。所有这些都是使用"new"创建的。我不明白为什么这不起作用。在我将一个新的结构指针推到向量后的一行,我无法读取它(正如我所说的分段错误(。

有什么想法吗?谢谢

编辑:对不起,这是valgrind的信息:

==13334== Invalid read of size 4
==13334==    at 0x804AEAE: SparseMatrix::SparseMatrix(int, int, std::vector<double,     std::allocator<double> >) (in /home/yotamoo/workspace/ex3/main)
==13334==    by 0x8048C10: main (in /home/yotamoo/workspace/ex3/main)
==13334==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
==13334== 
==13334== 
==13334== Process terminating with default action of signal 11 (SIGSEGV)
==13334==  Access not within mapped region at address 0x8
==13334==    at 0x804AEAE: SparseMatrix::SparseMatrix(int, int, std::vector<double,     std::allocator<double> >) (in /home/yotamoo/workspace/ex3/main)
==13334==    by 0x8048C10: main (in /home/yotamoo/workspace/ex3/main)
==13334==  If you believe this happened as a result of a stack
==13334==  overflow in your program's main thread (unlikely but
==13334==  possible), you can try to increase the size of the
==13334==  main thread stack using the --main-stacksize= flag.
==13334==  The main thread stack size used in this run was 8388608.

并且-在第一次迭代期间出现分段错误!

这是用于构造*_matrix:的std::vector<val *>构造函数

explicit vector ( size_type n, const val *& value = val *(), const std::allocator<val *>& = std::allocator<val *>() );

n设置为fill.size()的情况下调用该构造函数会创建具有fill.size()默认构造的val *对象(全部为NULL(的新std::vector<val *>。当推回新的val指针时,*_matrix具有fill.size() + 1元素,而_matrix->front()仍然是NULL指针。实际上,您正在取消引用NULL

您可能正在寻找reserve()方法。

编辑:我注意到还有一些其他可以改进的地方:

  1. SparseMatrix构造函数按值获取fill。这意味着,为了构建新的SparseMatrix,需要制作double对象的向量的完整副本。您应该通过const引用传递fill
  2. 对于STL容器迭代器,除非需要后增量的结果,否则应该始终使用前增量运算符
  3. 如果新val对象的某个分配引发std::bad_alloc异常,则会泄漏内存
  4. 考虑使用池分配器来分配许多val对象。一些C/C++运行库实现(例如OpenBSD(会随机化内存分配。在堆上分配许多小对象可能会导致严重的堆碎片化

如果numCol>fill.size(),循环将运行到底。

正如其他人所解释的,错误是使用nullptr初始化,而不是保留然后取消引用它们。

您还为所有项目保留了空间,而没有释放未使用的空间。您的稀疏数组将始终使用比传入的原始向量更多的空间。

您不应该为所有这些项目添加新内容。使用值的矢量。这将使您的代码异常安全。

还有一个问题是,你没有检查你是否有权填写。至少应该有一个关于元素数量的断言。

假设val是这样的结构:

struct val
{
     val( int x, int y, double value ):x(x),y(y),value(value){}
     int x;
     int y;
     double value;
};

那么一个改进/修正的版本可能是这样的:

class SparseMatrix
{
   vector<val> _matrix;
public:
    SparseMatrix(const int numRow, const int numCol, vector<double> const& fill)
    {
        assert( numCol > 0 );
        assert( numRow > 0 );
        assert( numRow * numCol == fill.size() );
        int skipped = std::count( fill.begin(), fill.end(), 0.0 );
        _matrix.reserve( fill.size() - skipped );
        vector<double>::const_iterator itr = fill.begin();
        for( int i=0; i<numRow; ++i)
        {
            for(int j=0; j<numCol; ++j, ++itr)
            {
                if( *itr != 0.0 )
                {
                    _matrix.push_back( val( i, j, *itr ) );
                }
            }
        }
    }
};