Returning local memory as reference from function

Pages: 12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <iostream>

///define a matrix class
///this is a large object that can hold big memory
class matrix
{
	int rows;
	int cols;
	double **mat;

	public:

	matrix( )
	{
		//default constructor
		rows = cols = 0;
		mat = 0;
	};

	//constructor
	matrix( int r, int c )
	{
		rows = r;
		cols = c;
		mat = new double* [ r ];
		for( int i = 0; i < r; ++i )
			mat[ i ] = new double [ c ];
	};

	//copy constructor -- method for initializing one matrix directly from another
	matrix( const matrix& other)
	{
		rows = other.rows;
		cols = other.cols;
		mat = new double* [rows];
		for( int i = 0; i < rows; ++i )
		{
			mat[i] = new double [ cols ];
			for( int j = 0; j < cols; ++j )
				mat[i][j] = other.mat[i][j];
		}
	};

	//destructor
	~matrix( )
	{
		for( int i = 0 ; i < rows; ++i )
			if( mat[i] ) delete [] mat[i];
		if( mat ) delete [] mat;
		mat = 0;
	};

	///overload operator +
	///the argument other is passed by reference to avoid temporary copies
	///return a reference in order to avoid temporary copies in stack
#ifndef USE_RETURN_POINTER
	matrix& operator+( const matrix &other )
	{
		matrix *m = new matrix ( other.rows, other.cols );//a memory allocated in global heap
		for( int i = 0; i < other.rows; i++ )
			for( int j = 0; j < other.cols; j++ )
				m->mat[i][j]  = mat[i][j] + other.mat[i][j];
		return *m;//a reference to the pointer is returned not the pointer itself
	};

#else	
	//this overloaded operator directly returns a pointer -- an alternative scheme for operator overload
	matrix* operator+( const matrix &other )
	{
		matrix *m = new matrix ( other.rows, other.cols );//a memory allocated in global heap
		for( int i = 0; i < other.rows; i++ )
			for( int j = 0; j < other.cols; j++ )
				m->mat[i][j]  = mat[i][j] + other.mat[i][j];
		return m;
	};
#endif

	//get a matrix element
	double &element(int i, int j) { return mat[i][j]; }

};



int main( )
{
	///initialize matrices -- big dense matrices
	matrix M1(1000,1000), M2(1000,1000);

	for( int i = 0; i < 1000; ++i )
	{
		for( int j = 0; j < 1000; ++j )
		{
			M1.element(i,j) = 1;
			M2.element(i,j) = 2;
		}
	}

	//do an addition operator
#ifndef USE_RETURN_POINTER
	matrix M3;
	M3 = M1 + M2;//use the return reference * operator
	std::cout << M3.element(500,500);

	///do not do the following
	//matrix M3 = M1 + M2;
	///this will invoke copy constructor which will allocate extra 1000x1000 matrix memory which I sought to avoid
        
#else
	matrix *M3;
	M3 = M1 + M2;
	std::cout << M3->element(500,500);

	delete M3;///delete M3 before exit
#endif

	return 0;
}
//now M1, M2 goes out of scope and are completely destroyed
//M3.mat is completely freed as per destructor, but what happens to the pointer m in line#59 which is not freed from global stack before program exits?

//-- END C++ Code------------------ 

///My Comments
Please consider the above class for initiating and adding dense matrices. I found a subtle difference between returning a matrix object as a reference and as a pointer. When returning the class as a reference the local pointer *m remained in the stack and was not freed before exit from program. As a proof if you compile the above program without -DUSE_RETURN_POINTER flag, you get the following leak with valgrind:

==2192== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2192== at 0x4A06FAC: operator new(unsigned long) (vg_replace_malloc.c:230)
==2192== by 0x400C14: matrix::operator+(matrix const&) (tryMat.cc:59)
==2192== by 0x400971: main (tryMat.cc:102)
==2192==
==2192== LEAK SUMMARY:
==2192== definitely lost: 16 bytes in 1 blocks. (A memory leak)

In contrast if you use the -DUSE_RETURN_POINTER flag there are 0 bytes lost during return. There were no other problems when I performed different operations with the matrix M3 returned as a reference from the overload function but I could not find a way to get rid of big memory leak when many such objects were used. The only way out seems to be the mechanism of returning a pointer. But then all matrix objects used has to be defined as pointers. Infact any local memory that is returned as a reference from any function has the same problem. Is there a way to not use pointer and return a matrix class without causing any memory errors?

Thank you
PS : My first post - so I am not sure if I followed the correct format
Last edited on
What kind of operator+ returns a reference? That doesn't make sense. Return a value and do not worry about the supposed copies.

And yes, if you lose the pointer returned by new, as you do in -DUSE_RETURN_POINTER, you have a memory leak, since that pointer is the only thing that can be passed to delete.

edit: Here's your program with operator+ fixed to return a value. I've added output statements into all functions. Copy ctor is not called: demo: http://ideone.com/fSDbU

also tested with gcc 4.6.2, clang++-3.0, intel 11.1, and visual studio 2010 release mode - no copy constructor was ever called. However, visual studio 2010 debug mode did call it.. which only serves as a reminder to use release mode :)
Last edited on
Cubbi

Thank you for your answer. But that does not solve the problem. I ran your changes on a 64 bit 2.6.9-89.ELlargesmp #1 SMP linux machine. I use the GNU g++ 4.4.2v for compiling. It gives the following output

ctor called
ctor called
op+ called
ctor called
dtor Called  --- the destructor is called before exit from overload function
Seg fault


With the -DUSE_RETURN_POINTER flag

ctor called
ctor called
ctor called
3
dtor Called
dtor Called
dtor Called


I changed the code to:
1
2
3
4
5
6
7
8
9
matrix operator+( const matrix &other )
        {
                std::cout << "op+ called\n";
                matrix m ( other.rows, other.cols );
                for( int i = 0; i < other.rows; i++ )
                        for( int j = 0; j < other.cols; j++ )
                                m.mat[i][j]  = mat[i][j] + other.mat[i][j];
                return m;//a reference to the pointer is returned not the pointer itself
        };


In gdb it shows where it seg-faults:
std::cout << M3.element(500,500);
(gdb) p M3
$1 = {rows = 1000, cols = 1000, mat = 0x154ffb0}
(gdb) p M3.mat
$2 = (double **) 0x154ffb0
(gdb) p M3.mat[0][0]
$3 = 1.0968646224650565e-312
(gdb) p M3.mat[1][1]
$4 = 3


I think the above shows the problem. The destructor is called to destroy the memory in local area before exit, and makes sense to me. I am not sure how you got a conflicting result between a release and debug mode -- in my build both debug and O2 build seg-faulted. Or else this is a compiler problem? THank you again for reply
I think there is a problem in the destructor , it must be .

1
2
3
4
5
6
7
8
9
//destructor
~matrix( )
{
for( int i = 0 ; i < rows; ++i )
if( mat[i] ) delete  mat[i];

if( mat ) delete [] mat;
mat = 0;
};
You are not using the program I posted to http://ideone.com/fSDbU

The hybrid program you ran exposed an unrelated bug: you don't have an assignment operator.

I'll write one for you:

1
2
3
4
5
6
7
        matrix& operator=(matrix other)
        {
            std::swap(rows, other.rows);
            std::swap(cols, other.cols);
            std::swap(mat, other.mat);
            return *this;
        }
Nope. mat[i] is still an array so it requires a delete [ ] mat[i]. With your change I got the following valgrind error with -DUSE_RETURN_POINTER flag:

==2409== Mismatched free() / delete / delete []
==2409== at 0x4A05DEF: operator delete(void*) (vg_replace_malloc.c:342)
==2409== by 0x400C28: matrix::~matrix() (tryMat.cc:52)
==2409== by 0x400A1E: main (tryMat.cc:119)
==2409== Address 0x5dad940 is 0 bytes inside a block of size 8,000 alloc'd
==2409== at 0x4A0686E: operator new[](unsigned long) (vg_replace_malloc.c:274)
==2409== by 0x400B23: matrix::matrix(int, int) (tryMat.cc:26)
==2409== by 0x400C8B: matrix::operator+(matrix const&) (tryMat.cc:75)
==2409== by 0x4009E5: main (tryMat.cc:116)
dtor Called
==2409==
==2409== Mismatched free() / delete / delete []
==2409== at 0x4A05DEF: operator delete(void*) (vg_replace_malloc.c:342)
==2409== by 0x400C28: matrix::~matrix() (tryMat.cc:52)
==2409== by 0x400A37: main (tryMat.cc:122)
==2409== Address 0x55fe230 is 0 bytes inside a block of size 8,000 alloc'd
==2409== at 0x4A0686E: operator new[](unsigned long) (vg_replace_malloc.c:274)
==2409== by 0x400B23: matrix::matrix(int, int) (tryMat.cc:26)
==2409== by 0x40095A: main (tryMat.cc:93)
dtor Called
==2409==
==2409== Mismatched free() / delete / delete []
==2409== at 0x4A05DEF: operator delete(void*) (vg_replace_malloc.c:342)
==2409== by 0x400C28: matrix::~matrix() (tryMat.cc:52)
==2409== by 0x400A5E: main (tryMat.cc:122)
==2409== Address 0x4e4f030 is 0 bytes inside a block of size 8,000 alloc'd
==2409== at 0x4A0686E: operator new[](unsigned long) (vg_replace_malloc.c:274)
==2409== by 0x400B23: matrix::matrix(int, int) (tryMat.cc:26)
==2409== by 0x400944: main (tryMat.cc:93)
==2409==
==2409== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 5 from 2)

I will try to obtain an advanced g++ version
I don't think there was a problem with the destructor. mat[i] points to an array so it is correct to use delete[].

Do you really need to test if the pointers are null in the destructor? If mat is null you have already accessed invalid memory in the loop above. You probably know that the pointers are never null and calling delete on a null pointer is perfectly safe anyway.

I think the problem can be that you don't declare an operator=. http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
Last edited on
After Cubbi's last comment it works. I am posting my whole code for the record.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <iostream>

///define a matrix class
///this is a large object that can hold big memory
class matrix
{
	int rows;
	int cols;
	double **mat;

	public:

	matrix( )
	{
		//default constructor
		rows = cols = 0;
		mat = 0;
	};

	//constructor
	matrix( int r, int c )
	{
		std::cout << "ctor called\n";
		rows = r;
		cols = c;
		mat = new double* [ r ];
		for( int i = 0; i < r; ++i )
			mat[ i ] = new double [ c ];
	};

	//copy constructor -- method for initializing one matrix directly from another
	matrix( const matrix& other)
	{
		std::cout << "copy ctor called\n";
		rows = other.rows;
		cols = other.cols;
		mat = new double* [rows];
		for( int i = 0; i < rows; ++i )
		{
			mat[i] = new double [ cols ];
			for( int j = 0; j < cols; ++j )
				mat[i][j] = other.mat[i][j];
		}
	};

	//destructor
	~matrix( )
	{
		std::cout << "dtor Called\n";
		for( int i = 0 ; i < rows; ++i )
			if( mat[i] ) delete [] mat[i];
		if( mat ) delete [] mat;
		mat = 0;
		rows = cols = 0;
	};

	///overload operator +
	///the argument other is passed by reference to avoid temporary copies
	///return a reference in order to avoid temporary copies in stack
#ifndef USE_RETURN_POINTER
	matrix operator+( const matrix &other )
	{
		std::cout << "op+ called\n";
		matrix m ( other.rows, other.cols );
		for( int i = 0; i < other.rows; i++ )
			for( int j = 0; j < other.cols; j++ )
				m.mat[i][j]  = mat[i][j] + other.mat[i][j];
		return m;
	};

#else	
	//this overloaded operator directly returns a pointer -- an alternative scheme for operator overload
	matrix* operator+( const matrix &other )
	{
		matrix *m = new matrix ( other.rows, other.cols );//a memory allocated in global heap
		for( int i = 0; i < other.rows; i++ )
			for( int j = 0; j < other.cols; j++ )
				m->mat[i][j]  = mat[i][j] + other.mat[i][j];
		return m;
	};
#endif

	 matrix& operator=(matrix other)
	 {
                std::cout << "In = operator\n";
		 std::swap(rows, other.rows);
		 std::swap(cols, other.cols);
		 std::swap(mat, other.mat);
		 return *this;
	 }

	//get a matrix element
	double &element(int i, int j) { return mat[i][j]; }

};



int main( )
{
	///initialize matrices -- big dense matrices
	matrix M1(1000,1000), M2(1000,1000);

	for( int i = 0; i < 1000; ++i )
	{
		for( int j = 0; j < 1000; ++j )
		{
			M1.element(i,j) = 1;
			M2.element(i,j) = 2;
		}
	}

	//do an addition operator
#ifndef USE_RETURN_POINTER
	matrix M3;
	M3 = M1 + M2;//use the return reference * operator
	std::cout << M3.element(500,500) << "\n" ;

	///do not do the following
	//matrix M3 = M1 + M2;
	///this will invoke copy constructor which will allocate extra 1000x1000 matrix memory which I sought to avoid
        
#else
	matrix *M3;
	M3 = M1 + M2;
	std::cout << M3->element(500,500) << "\n" ;

	delete M3;///delete M3 before exit
#endif

	return 0;
}
//now M1, M2 goes out of scope and are completely destroyed
//M3.mat is completely freed as per destructor, but what happens to the pointer m in line#59 which is not freed from global stack before program exits? 


The following are the outputs
without the -DUSE_RETURN_POINTER flag

ctor called
ctor called
op+ called
ctor called
In = operator
dtor Called
3
dtor Called
dtor Called
dtor Called

No memory problems with valgrind.
Thanks Cubbi for your help.
I am still confused about why dtor is being called before exit of the function. If possible please explain. I will try to understand the logic.

Thanks to Peter87 for comments.
Last edited on
The dtor you're seeing before the line "3" is the destruction of the empty temporary object that used to be the matrix M3 (but was swapped out inside operator=)


Instead of
1
2
matrix M3;
M3 = M1 + M2;
use
matrix M3 = M1 + M2;

that's good coding practice and it will save you a ctor and a dtor calls.
Another comment - I think the call to destructor is okay since the variable is going out of scope. The program required swapping operations in the = operator code as Cubbi pointed out. For example code with the following seg-faulted:
1
2
3
4
5
6
7
  matrix& operator=(matrix other)
        {
            rows = other.rows;
            cols = other.cols;
            mat = other.mat;
            return *this;
        }

Since it requires the swapping operation in =operator , the whole logic is still confusing.
Is there any benefits of using swap in operator=?

1
2
3
4
5
6
7
matrix& operator=(matrix other)
{
	std::swap(rows, other.rows);
	std::swap(cols, other.cols);
	std::swap(mat, other.mat);
	return *this;
}


1
2
3
4
5
6
7
matrix& operator=(const matrix& other)
{
	rows = other.rows;
	cols = other.cols;
	mat = other.mat;
	return *this;
}
Peter87: pass-by-value and swap is the proper way to write copy-assignment operators in C++.

The problems with your other approach are

1) duplicating the code of the copy constructor (note that your "mat = other.mat;" is incorrect and needs to be replaced by the loop used in the destructor followed by the loop used in copy constructor, unless the sizes match, in which case you just replicate the copy-constructor loop)

2) prohibiting copy elision (notice that in the output of that program, no copy was made. The manual approach would require a manual copy which is unlikely to be optimized out)

3) failure to make use of move semantics (if someone calls this operator with xvalue, in C++11, the pass-by-value-and-swap solution will not make the unnecessary copy either)
Last edited on
Swap in operator= is NOT required for the code to work. The last operator= code is fine from Peter. The following is required as per Cubbi's last remark.
Matrix M3 = M1 + M2;

With the following function:
1
2
3
4
5
6
7
matrix& operator=(const matrix& other)
{
	rows = other.rows;
	cols = other.cols;
	mat = other.mat;
	return *this;
}


With the following assignments for M3:
1
2
Matrix M3;
M3 = M1 + M2

The above segfaults


ctor called
ctor called
op+ called
ctor called
In = operator
dtor Called
Segmentation fault


so we need
 
Matrix M3 = M1 + M2;


for successful run without leaks.

ctor called
ctor called
op+ called
ctor called
3
dtor Called
dtor Called
dtor Called
Last edited on
@Indranil Chowdhury the line Matrix M3 = M1 + M2; has nothing to do with assignment.
Cubbi: ok make sense. But if you want to make it more efficient I think you can do that by reusing the old arrays to store the new data.

The code assumes that the size of the matrices are the same.
matrix(10,10) + matrix(100,100); // this will compile but it's not correct
Last edited on
There is lots of issues about this code. As the question is about memory leaks, I can start by saying that you NEVER EVER should return a reference from a function, unless it's a part of the input. There's several reasons for this, in your case it's about memory leaks, because you're not using delete on a dynamically allocated object... hence a memory leak.

Lets take it from the top and walk through the problems with the code.
The first 2 constructors are fine.

The Copy constructor does not check if other.mat is a NULL pointer, and will fail if you'd do something like this (crashes):
matrix m( matrix() )

The Destructor has the same problem as the Copy constructor - it doesn't check if
mat is a NULL pointer. So this would fail (crashes):
1
2
matrix * m = new matrix;
delete m;


The operator+ overload:
First of all - this operator should only work if the matrix sizes are equal, therefore a call like this will fail - and cause a crash - as Peter87 said:
1
2
3
4
5
6
7
8
matrix m1(500, 500), m2(600, 600), m3;
for (int i=0; i<600; ++i)
    for (int j=0; j<600; ++j) {
        if (i < 500 && j < 500)
            m1.element(i, j) = 1;
        m2.element(i, j) = 2;
    }
m3 = m1 + m2;


As I said earlier - you should NEVER dynamically allocate and return a pointer/reference to something that requires a delete operation. Instead you should do what Cubbi suggested.
However this will cause a copy on assignment, unless your compiler is smart enough to remove that copy with optimizing. This is a known issue about C++98 or earlier, there is no way around it unless you code in an memory leak prone way, such as returning a pointer to a dynamically allocated object - like you did.

However! If you're using C++0x/C++11 you can make use of the rvalue references, and write an assignment operator function like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Old fashion assignment operator
matrix& operator=(const matrix & other)
{
    // We are forced to copy here..
    cols = other.cols;
    rows = other.rows;
    
    // Remove any old data
    if (!mat) {
        for( int i = 0 ; i < rows; ++i )
	    if( mat[i] ) delete [] mat[i];
        if( mat ) delete [] mat;
    }

    // Init mat and copy over the data from other
    mat = new double* [rows];
    for( int i = 0; i < rows; ++i )
    {
        mat[i] = new double [ cols ];
        for( int j = 0; j < cols; ++j )
            if (!other.mat && !other.mat[i])
		mat[i][j] = other.mat[i][j];
            else
                mat[i][j] = 0;
    }

    return *this;
}

// C++0x/C++11: rvalue reference assignment operator
matrix& operator=(matrix && other)
{
    cols = other.cols;
    rows = other.rows;
    mat = other.mat;

    other.cols = other.rows = 0;
    other.mat = 0;
    return *this;
}


The code above will make your...
M3 = M1 + M2;
...statement call the rvalue reference version of the assignment operator. This call only copies
an address to your matrix, and not the matrix itself, therefore you're only copying a few bytes, 2 ints and a pointer.

You can also use rvalue references to create a copy constructor - in the exact same way as the assignment operator so that it too uses rvalue references whenever it can.

Hope it helps!
// Sorglig
Last edited on
@Sorglig, the usual copy and swap assignment operator that I posted earlier works for both lvalues and rvalues, there's no need in the dedicated move-assignment operator (assuming the move ctor exists).
@Cubbi, that is true... tho it works implicitly (which is nice if you know it) and not explicitly like my example which I hope makes it a bit easier to grasp. Noticed now that you even said that in an earlier post :p. My bad!
Last edited on
I am posting my latest code. The objective here is how to return a local memory from a function - from above comments the rules are "NEVER dynamically allocate and return a pointer/reference to something that requires a delete operation" , and using "pass-by -value and swap for = operations". I have also put an example function that returns an object using these mechanisms.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>

///A matrix that can hold big memory
class matrix
{
	int rows;
	int cols;
	double **mat;

	public:

	matrix( )
	{
		//default constructor
		rows = cols = 0;
		mat = 0;
	};

	//constructor
	matrix( int r, int c )
	{
		std::cout << "ctor called\n";
		rows = r;
		cols = c;
		mat = new double* [ r ];
		for( int i = 0; i < r; ++i )
			mat[ i ] = new double [ c ];
	};

	//copy constructor -- method for initializing one matrix directly from another
	matrix( const matrix& other)
	{
		std::cout << "copy ctor called\n";
		rows = other.rows;
		cols = other.cols;
		mat = new double* [rows];
		for( int i = 0; i < rows; ++i )
		{
			mat[i] = new double [ cols ];
			for( int j = 0; j < cols; ++j )
				mat[i][j] = other.mat[i][j];
		}
	};

	//destructor
	~matrix( )
	{
		std::cout << "dtor Called\n";
		for( int i = 0 ; i < rows; ++i )
			if( mat[i] ) delete [] mat[i];
		if( mat ) delete [] mat;
		mat = 0;
		rows = cols = 0;
	};

	///overload operator +
	matrix operator+( const matrix &other )
	{
		std::cout << "op+ called\n";
		matrix m ( other.rows, other.cols );
		for( int i = 0; i < other.rows; i++ )
			for( int j = 0; j < other.cols; j++ )
				m.mat[i][j]  = mat[i][j] + other.mat[i][j];
		return m;
	};

	///this is pass-by-value and swap for = operation as per last comments
	 matrix& operator=(matrix other)
	 {
		 std::cout << "operator= called\n";
		 std::swap(rows, other.rows);
		 std::swap(cols, other.cols);
		 std::swap(mat, other.mat);
		 return *this;
	 }

        //an example for returning matrix from general function
	 static matrix myFunc( matrix &mat1  )
	 {
		std::cout << "In myFunc1\n";
		matrix m(mat1.rows,mat1.cols);
		for( int i = 0; i < mat1.rows; ++i )
			for( int j = 0; j < mat1.cols; ++j )
				m.mat[i][j] = 2.0 * mat1.mat[i][j];

		return m;
	 }

	//get a matrix element
	double &element(int i, int j) { return mat[i][j]; }

};

//I un-learnt that it is safe to return references / pointers of new objects from functions with local memories

int main( )
{
	///initialize matrices -- big dense matrices
	matrix M1(1000,1000), M2(1000,1000);

	for( int i = 0; i < 1000; ++i )
	{
		for( int j = 0; j < 1000; ++j )
		{
			M1.element(i,j) = 1;
			M2.element(i,j) = 2;
		}
	}

	//do an addition operator
	matrix M3 = M1 + M2;
	std::cout << M3.element(500,500) << "\n" ;

	//return matrix from a general function
	matrix M4 = matrix::myFunc ( M2 );
	std::cout << M4.element(500,500) << "\n" ;

	//invoke copy constructor
	matrix M5 = M1;
	std::cout << M5.element(500,500) << "\n";

	return 0;
}


Output

ctor called
ctor called
op+ called
ctor called
3
In myFunc1
ctor called
4
copy ctor called
1
dtor Called
dtor Called
dtor Called
dtor Called
dtor Called

Ran without memory leaks. Eactly 5 ctors and dtors are called during execution.

There may be other logical flaws in implementation of individual functions and other parts where the program will crash, just as sorglig says. But that is not the objective of this thread - I want to learn just how do I return a NEW large object from a function correctly (i) without crashing or memory leaks (ii) invoking of temporary copies in local stacks (iii)avoid destructor calls when return . In the above code the two functions are + operator and myFunc. I have the following questions:
1. what is the difference between Matrix M5 = M1, which invokes the copy constructor and Matrix M4=myfunc(). One invokes copy ctor, the other does not.
2. The statement in operator= ""operator= called\n" around line 70 is not being flashed in output. I don't know the reason.
3. is the above mechanism for returning a large new object from a function correct

Cubbi - if possible please give me a reference where I can understand the issues like "pass-by-value-and-swap" and "copy elision". Thank you.
1. what is the difference between Matrix M5 = M1, which invokes the copy constructor and Matrix M4=myfunc(). One invokes copy ctor, the other does not.

Matrix M5 = M1; tells the compiler to copy-construct M5 from M1, nothing special

Matrix M4 = myfunc(); tells the compiler to either copy-construct M4 from the return of myfunc(), or to perform copy elision if possible. In this case it is possible, the conditions for NRVO (named return value optimization) are met. Matrix M4 from main() and matrix m from myfunc() become one and the same object. The object is located in main()'s stack frame, but is constructed at line 81. The return statement from line 86 doesn't even happen.

2. The statement in operator= ""operator= called\n" around line 70 is not being flashed in output. I don't know the reason.

There are no assignments in your program now, operator= is never called.

3. is the above mechanism for returning a large new object from a function correct
Yes. In some other non-optimizing compilers (such as Visual Studio in Debug mode), it may generate an unnecessary copy. There are ways to improve this further, but first you may consider learning to avoid manual memory management: build your matrix around a 1D vector. It will both improve efficiency and simplify the program.
Pages: 12