Search code examples
c++templatescudacopy-constructorassignment-operator

Eternal assignment operator call loop C++ template class


I have a matrix class with a subset of its member functions included,

#ifndef _CMATRIX_CUH_
#define _CMATRIX_CUH_

#include <thrust/device_vector.h>
#include <assert.h>
template<class T>
class CMatrix
{
private:

    size_t n_rows, n_cols;
    
    T **data;

    __host__ __device__ void allocate_data();

    __host__ __device__ void deallocate_data();
    
public:

    __host__ __device__ CMatrix(const size_t n_rows);

    __host__ __device__ CMatrix(const size_t n_rows, const size_t n_cols);

    __host__ __device__ CMatrix(const CMatrix &other);

    __host__ __device__ ~CMatrix();

    __host__ __device__ CMatrix& operator=(const CMatrix &rhs);
}

/****************************************************************************************
*  Name     : CMatrix
*  Function : Class constructor, initializes parameters and variables
*  Method   : 
*  Author   : 
*  Modified :
*****************************************************************************************/
template <class T>
__host__ __device__ CMatrix<T>::CMatrix(
    const size_t n_rows                                         // In: Amount of matrix rows
    ) :
    n_rows(n_rows), n_cols(n_rows)
{
    allocate_data();
}

template <class T>
__host__ __device__ CMatrix<T>::CMatrix(
    const size_t n_rows,                                        // In: Amount of matrix rows
    const size_t n_cols                                         // In: New amount of matrix columns
    ) :
    n_rows(n_rows), n_cols(n_cols)
{
    allocate_data();
}

template <class T>
__host__ __device__ CMatrix<T>::CMatrix(
    const CMatrix<T> &other                                     // In: Matrix/vector to copy
    ) :
    n_rows(other.n_rows), n_cols(other.n_cols)
{
    allocate_data();
    for (size_t i = 0; i < n_rows; i++)
    {
        for (size_t j = 0; j < n_cols; j++)
        {
            data[i][j] = other.data[i][j];
        }
    }
}

/****************************************************************************************
*  Name     : ~CMatrix
*  Function : Class destructor
*  Method   : 
*  Author   : 
*  Modified :
*****************************************************************************************/
template <class T>
__host__ __device__ CMatrix<T>::~CMatrix()
{
    deallocate_data();
}

/****************************************************************************************
*  Name     : operator=
*  Function : 
*  Author   : 
*  Modified :
*****************************************************************************************/
template <class T>
__host__ __device__ CMatrix<T>& CMatrix<T>::operator=(
    const CMatrix<T> &rhs                                       // In: Right hand side matrix/vector to assign
    )
{
    if (this == &rhs)
    {
        return *this;
    }
    deallocate_data();

    return *this = CMatrix<T>(rhs);
}

/****************************************************************************************
    Private functions
****************************************************************************************/
/****************************************************************************************
*  Name     : allocate_data
*  Function : 
*  Author   : 
*  Modified :
*****************************************************************************************/
template <class T>
__host__ __device__ void CMatrix<T>::allocate_data()
{
    assert(n_rows > 0 && n_cols > 0);
    data = new T*[n_rows];
    for (size_t i = 0; i < n_rows; i++)
    {
        data[i] = new T[n_cols];
    }
}

/****************************************************************************************
*  Name     : deallocate_data
*  Function : 
*  Author   : 
*  Modified :
*****************************************************************************************/
template <class T>
__host__ __device__ void CMatrix<T>::deallocate_data()
{
    if (data == nullptr)
    {
        return;
    }

    for (size_t i = 0; i < n_rows; i++)
    {
        delete[] data[i];
    }
    delete[] data;
    data = nullptr;
}

#endif

which, when I in a main() function call the assignment operator

CMatrix<double> t1(2);
CMatrix<double> t2(3);
t1 = t2;

the stack winds up in a segmentation fault as the assignment operator calls itself over and over and never returns, why? I have no idea what is causing it, after long time debugging. Isnt this textbook Rule of three? I am using const references and return reference from the assignment. And yes, I know I could use std:: etc, the problem is that is not possible in Cuda after what I know.


Solution

  • The assignment operator CMatrix::operator= calls itself recursively.

    template <class T>
    __host__ __device__ CMatrix<T>& CMatrix<T>::operator=(
        const CMatrix<T> &rhs                                       // In: Right hand side matrix/vector to assign
        )
    {
        ...
    
        return *this = CMatrix<T>(rhs);  // calls operator=
    }