Search code examples
c++gsl

C++ strange behaviour with function call by value


I have an object which is a class interface to the matrix struct found in the GNU Scientific Library

typedef double real_t;
typedef unsigned short index_t;
class matrix
{
        gsl_matrix* m;
    public:
        matrix(index_t rows, index_t columns, real_t val);
}

matrix::matrix(index_t rows, index_t columns, real_t val)
{
    m=gsl_matrix_alloc(rows,columns);
    gsl_matrix_set_all(m, val);
    return;
}

index_t matrix::rows(void)
{
    return m->size1;
}

index_t matrix::columns(void)
{
    return m->size2;
}

the problem is that if I use a function taking the matrix object by value like this one:

void test_function(const matrix m){};

and use it in a program like this one

int main()
{
    matrix m(4,4,1);
    cout << m.rows() << '\t' << m.columns() << endl;
    test_function(m);
    cout << m.rows() << '\t' << m.columns() << endl;
}

I surprisingly obtain that the number of rows of the matrix object m is modified by the function test_function to garbage value, even if I put the keyword const before the argument and the call is made by value. But the strangest thing is that if I use a function that makes use of call by reference like this one:

void test_function(const matrix &m){};

nothing happens and everything seems to be all right.

As far as I know, call by value shouldn't be able to modify the argument of the function, especially if the function does nothing as in this case and especially if I explicitly use the keyword const before the argument name in the function prototype...

Any help would be greatly appreciated.

EDIT:

I also have defined the copy constructor for the matrix class as

matrix& matrix::operator= (const matrix& src)
{
    gsl_matrix_memcpy(m,src.m);
    return *this;
}

which does a complete copy (I guess) of the gsl_matrix struct

EDIT:

Ok, I think I've finally understood: the call by value function creates a shallow copy object that just contains the pointer to the real object, when test_function terminates all local variables are destroyed, so the destructor of the matrix class (which is defined but omitted here for the sake of brevity) is called, but in this way the object in the main (to which the local m points to) is destroyed together with the local variable.. Anyway I solved the problem defining a proper copy constructor that performs a complete (deep) copy of the object and then using call by reference which should be better for heavy computation. Thanks a lot to everybody for your help!


Solution

  • When you pass an argument by value, compiler calls the one-argument copy constructor to create the value in the function. If you do not provide a copy constructor, compiler generates one for you.

    In the example above, compiler generated copy constructor makes shallow copy of the inner matrix pointer. When the newly generated matrix in the function goes out of scope, the shallow copied pointer gets deleted also. My guess is this is the reason.

    You could check this by providing a copy constructor which does not copy the gsl_matrix pointer.