尝试从此指针复制后访问基类成员的段错误

时间:2013-04-21 06:52:36

标签: c++ oop c++11

我要提前为巨大的代码块道歉 - 我尽力将其归结为一个测试用例。

我的程序在标有注释的行上的vectorTest.cpp中抛出了一个段错误。正如那里的评论所示,我已经跟踪了段{f}中的段错误。

问题似乎是我无法访问Matrix.h::Matrix< T >::operator[]。这很奇怪,因为从O.rref()::rrefMatrix._values的其余部分可以看到,访问vectorTest.cppM._valuesM.rref()::rrefMatrix._values时没有问题。只有当我使用O._values后面的<{1>}函数 append()时才会遇到我的错误。

我只是在绳子尽头。有人可以请我解释一下吗?

vectorTest.cpp:

Matrix< T >::rref()

Matrix.h:

#include "Vector.h"
#include "Polynomial.h"
#include "Matrix.h"

#include <iostream>

using namespace std;

int main( int argc, char* argv[] )
{
    Matrix< float > M( 3, 3 );
    M.setValues( { 1, 2, 3, 4, 5, 6, 7, 8, 8 } );

    cout << M << endl;

    cout << M.rref() << endl;

    Matrix< float > N( 3, 1 );
    N.setValues( { 2, -2, 5 } );

    Matrix< float > O = append( M, N );

    cout << O << endl;

    cout << O.rref() << endl; //Segfault!

    return 0;
}

Vector.h:

#ifndef __INCL_MATRIX_H__
#define __INCL_MATRIX_H__

#include "Vector.h"
#include <iterator>
#include <algorithm>
#include <utility>
#include <initializer_list>
#include <type_traits>
#include <iomanip>
#include <sstream>
#include <cassert>

template < class T >
class Matrix
    : Vector< T >
{
public:
    Matrix() :
        Vector< T >::Vector()
        {};
    Matrix( const Matrix< T >& cMatrix ) :
        Vector< T >::Vector( cMatrix ),
        _numRows( cMatrix._numRows ),
        _numColumns( cMatrix._numColumns )
        {};
    Matrix( const unsigned int r, const unsigned int c ) :
        _numRows( r ),
        _numColumns( c )
        {
            _values.reserve( r * c );
            for( unsigned int r = 0; r < _numRows; r++ )
                for( unsigned int c = 0; c < _numColumns; c++ )
                    _values[ r * _numColumns + c ] = T( 0 );
        }

    Matrix< T >& operator= ( const Matrix< T >& );

    template < class InputIterator >
        typename std::enable_if< std::is_same< T, typename std::iterator_traits< InputIterator >::value_type >::value, void >::type
            setValues( InputIterator, InputIterator );

    void setValues( std::initializer_list< T > );

    T* operator[] ( const unsigned int );
    const T* operator[] ( const unsigned int ) const;

    unsigned int numRows() const;
    unsigned int numColumns() const;

    Matrix< T > rref() const;

protected:
    void swapRows( const unsigned int, const unsigned int );

private:
    using Vector< T >::_values;

    unsigned int _numRows;
    unsigned int _numColumns;
};


template < class T >
Matrix< T >& Matrix< T >::operator= ( const Matrix< T >& cMatrix )
{
    _numRows = cMatrix._numRows;
    _numColumns = cMatrix._numColumns;
    _values = cMatrix._values;

    return *this;
}

template < class T >
template < class InputIterator >
typename std::enable_if< std::is_same< T, typename std::iterator_traits< InputIterator >::value_type >::value, void >::type Matrix< T >::setValues( InputIterator begin, InputIterator end )
{
    _values.clear();
    for( auto it = begin; it != end; it++ )
        if( _values.size() < _numRows * _numColumns )
            _values.push_back( *it );
}

template < class T >
void Matrix< T >::setValues( std::initializer_list< T > iList )
{
    setValues( iList.begin(), iList.end() );
}

template < class T >
T* Matrix< T >::operator[] ( const unsigned int r )
{
    return &( _values[ r * _numColumns ] ); //This is the thorn in my paw.
}

template < class T >
const T* Matrix< T >::operator[] ( const unsigned int r ) const
{
    return &( _values[ r * _numColumns ] );
}

template < class T >
unsigned int Matrix< T >::numRows() const
{
    return _numRows;
}

template < class T >
unsigned int Matrix< T >::numColumns() const
{
    return _numColumns;
}

template < class T >
constexpr T abs( const T a )
{
    return ( a < 0 ) ? -a : a;
}

template < class T >
constexpr T gcd( const T a, const T b )
{
    return ( a == b || b == 0 ) ? a : ( ( a < b ) ? gcd( abs( b ), abs( a ) ) : gcd( abs( a ) - abs( b ), abs( b ) ) );
}

template < typename T, typename... Ts >
constexpr T gcd( const T a, const T b, const Ts... others )
{
    return gcd( gcd( a, b ), others... );
}

template < class T >
Matrix< T > Matrix< T >::rref() const
{
    Matrix< T > rrefMatrix = (*this);
    unsigned int p = rrefMatrix._numColumns;
    T mult = 0, mult1 = 0, mult2 = 0;

    for( unsigned int r1 = 0; r1 < rrefMatrix._numRows; r1++ )
    {
        p = rrefMatrix._numColumns;
        for( unsigned int r2 = r1; r2 < rrefMatrix._numRows; r2++ )
        {
            for( unsigned int c = 0; c < rrefMatrix._numColumns; c++ )
            {
                if( rrefMatrix[r2][c] != T( 0 ) ) // Why is this segfaulting?
                {
                    p = c;
                    break;
                }
            }
            if( p != rrefMatrix._numColumns )
            {
                if( r2 > r1 )
                {
                    rrefMatrix.swapRows( r1, r2 );
                }
                break;
            }
        }
        if( p == rrefMatrix._numColumns )
            break;

        for( unsigned int r2 = 0; r2 < rrefMatrix._numRows; r2++ )
        {
            if( r1 == r2 ) continue;

            mult = gcd( rrefMatrix[r1][p], rrefMatrix[r2][p] );

            mult1 = mult * rrefMatrix[r2][p];
            mult2 = mult * rrefMatrix[r1][p];

            for( unsigned int c = 0; c < rrefMatrix._numColumns; c++ )
            {
                rrefMatrix[r1][c] *= mult1;
                rrefMatrix[r2][c] *= mult2;
            }

            for( unsigned int c = 0; c < rrefMatrix._numColumns; c++ )
            {
                rrefMatrix[r2][c] -= rrefMatrix[r1][c];
                rrefMatrix[r1][c] /= mult1;
            }
        }
    }

    for( unsigned int r = 0; r < rrefMatrix._numRows; r++ )
    {
        p = _numColumns;
        for( unsigned int c = 0; c < rrefMatrix._numColumns; c++ )
        {
            if( rrefMatrix[r][c] != 0 )
            {
                p = c;
                break;
            }
        }

        if( p == rrefMatrix._numColumns ) continue;

        mult = rrefMatrix[r][p];

        for( unsigned int c = 0; c < rrefMatrix._numColumns; c++ )
            rrefMatrix[r][c] /= mult;
    }

    return rrefMatrix;
}

template < class T >
void Matrix< T >::swapRows( const unsigned int r1, const unsigned int r2 )
{
    for( unsigned int c = 0; c < _numColumns; c++ )
        std::swap( (*this)[r1][c], (*this)[r2][c] );
}

template < class T >
unsigned int strLength( T& item )
{
    std::stringstream ss;
    ss << item;
    return ss.str().length();
}

template < class T >
std::ostream& operator<< ( std::ostream& out, const Matrix< T >& cMatrix )
{
    unsigned int maxLength = 0, currLength = 0;

    for( unsigned int r = 0; r < cMatrix.numRows(); r++ )
        for( unsigned int c = 0; c < cMatrix.numColumns(); c++ )
        {
            currLength = strLength( cMatrix[r][c] );
            if( currLength > maxLength )
                maxLength = currLength;
        }

    for( unsigned int r = 0; r < cMatrix.numRows(); r++ )
    {
        for( unsigned int c = 0; c < cMatrix.numColumns(); c++ )
            out << std::setw( maxLength ) << cMatrix[r][c] << ' ';
        out << std::endl;
    }

    return out;
}

template < class T >
Matrix< T > append( const Matrix< T >& lhs, const Matrix< T >& rhs )
{
    Matrix< T > appendMatrix( lhs.numRows(), lhs.numColumns() + rhs.numColumns() );

    for( unsigned int r = 0; r < appendMatrix.numRows(); r++ )
    {
        for( unsigned int c = 0; c < lhs.numColumns(); c++ )
        {
            appendMatrix[r][c] = lhs[r][c];
        }

        for( unsigned int c = 0; c < rhs.numColumns(); c++ )
        {
            appendMatrix[r][ c + lhs.numColumns() ] = rhs[r][c];
        }
    }

    return appendMatrix;
}

#endif

输出:

#ifndef __INCL_VECTOR_H__
#define __INCL_VECTOR_H__

#include <vector>
#include <iostream>
#include <iterator>
#include <initializer_list>
#include <type_traits>
#include <assert.h>

struct VectorBase {};

template < class T >
class Vector
    : public VectorBase
{
public:
    Vector()
        {};
    Vector( const Vector< T >& cVector ) :
        _values( cVector._values )
        {};
    template < class InputIterator >
        Vector( InputIterator first, InputIterator last ) :
            _values( first, last )
            {};
    Vector( std::initializer_list< T > iList ) :
        _values( iList.begin(), iList.end() )
        {};

protected:
    std::vector< T > _values;
};

#endif

1 个答案:

答案 0 :(得分:2)

在这个构造函数中:

Matrix( const unsigned int r, const unsigned int c ) :
    _numRows( r ),
    _numColumns( c )
    {
        _values.reserve( r * c );
        for( unsigned int r = 0; r < _numRows; r++ )
            for( unsigned int c = 0; c < _numColumns; c++ )
                _values[ r * _numColumns + c ] = T( 0 );
    }

改变这个:

        _values.reserve( r * c );

对此:

        _values.resize( r * c );

请参阅std::vector<>::reserve()的文档了解原因。它设定了容量;不是大小。这意味着您可以将向量增长到指定的容量,而不会触发内部重新分配以及可能被复制的对象。

注意:我会认真考虑使用基于rc的预定大小的构建向量的重组。