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

Posted

技术标签:

【中文标题】构造函数中的分段错误不明确【英文标题】:Unclear segmentation fault in a constructor 【发布时间】:2011-09-10 20:49:58 【问题描述】:

我已经为矩阵对象构建了一个构造函数。数据存储在结构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 在堆上,所有保存在其中的结构也是如此。全部使用“新”创建。我不明白为什么这不起作用。在我将一个新的结构指针推送到向量后的一行我无法读取它(正如我所说的分段错误)。

有什么想法吗?谢谢!

编辑: 抱歉,这是 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.

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

【问题讨论】:

gdb 告诉你什么?瓦尔格林?为什么要存储指针? 【参考方案1】:

这是用于构造*_matrixstd::vector&lt;val *&gt; 构造函数:

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

n 设置为fill.size() 的情况下调用该构造函数会创建一个新的std::vector&lt;val *&gt;,其中包含fill.size() 默认构造的val * 对象(所有NULL)。当你推回一个新的 val 指针时,*_matrixfill.size() + 1 元素,_matrix-&gt;front() 仍然是一个 NULL 指针。实际上,您正在取消引用 NULL

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

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

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

【讨论】:

【参考方案2】:

如果numCol > fill.size(),您的循环将结束。

【讨论】:

【参考方案3】:

正如其他人所解释的那样,错误是您正在使用 nullptrs 进行初始化,而不是保留然后取消引用它们。

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

您不应该对所有这些项目进行更新。使用值向量。这将使您的代码异常安全。

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

假设 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 ) );
                
            
        
    
;

【讨论】:

以上是关于构造函数中的分段错误不明确的主要内容,如果未能解决你的问题,请参考以下文章

由于构造函数,即将出现分段错误

带有 QWidget 的分段错误构造函数。 Qt/C++

为啥此 C++ 代码中的构造函数不明确,我该如何解决?

构造函数内部变量的定义会导致分段错误

为啥看似明确的类型提示构造函数调用存在“没有匹配的 ctor”?

具有显式构造函数的类是不是需要在 emplace 中使用分段构造?