.NET, Programming Tutorial

Never pass a local object to other functions by value

Introduction:
This post shows you what will be happened when we pass a local object to other function. Let’s see this code to know clearly what I say.

<strong>MyClass.h</strong>
#ifndef __INCLUDED_MYCLASS_H__
#define __INCLUDED_MYCLASS_H__

#include
#include

using namespace std;

class MyClass {
private:
	int* m_int;

public:
	MyClass();

	~MyClass();

	void ViewInt();

};

#endif // __INCLUDED_MYCLASS_H__

MyClass.cpp

#include "MyClass.h"

MyClass::MyClass() {
	m_int = new int;
	*m_int = 10;
}

MyClass::~MyClass() {
	if(m_int != NULL) {
		delete m_int;
		m_int = NULL;
	}
}

void MyClass::ViewInt() {
	cout << "Value of m_int: " << *m_int << endl;
}

main.cpp

#include "MyClass.h"

using namespace std;

void Func(MyClass m) {
	m.ViewInt();
}

int main() {
	MyClass m;
	Func(m);
	return 0;
}

Explaination:
We have a class named MyClass. Its constructor will dynamic initialize the m_int filed.
In main function, we have an object named m.
Next, we pass this object to the Func function, we try to get m_int value and print out to screen.
OK, now, everything is very easy to understand. Run this code and see what we will receive

The output result:
Value of m_int: 10
—— CRASH ——-

Oh no, we got crashed. But don’t worry, let’s do some debugging to know how the code run

MyClass.h

#ifndef __INCLUDED_MYCLASS_H__
#define __INCLUDED_MYCLASS_H__

#include
#include

using namespace std;

class MyClass {
private:
	int* m_int;

public:
	MyClass();

	~MyClass();

	void ViewInt();

};

#endif // __INCLUDED_MYCLASS_H__

MyClass.cpp

#include "MyClass.h"

MyClass::MyClass() {
	m_int = new int;
	*m_int = 10;
	cout << "[Constructor] Address of m_int: " << m_int << endl;
}

MyClass::~MyClass() {
	cout << "[Destructor] Address of m_int: " << m_int << endl;
	if(m_int != NULL) {
		delete m_int;
		m_int = NULL;
	}
}

void MyClass::ViewInt() {
	cout << "[ViewInt] Value of m_int: " << *m_int << endl;
}

main.cpp

#include "MyClass.h"

#include

using namespace std;

void Func(MyClass m) {
	m.ViewInt();
	cout << "[Func] Within call Func" << endl;
}

int main() {
	cout << "[main] Before declare m" << endl;
	MyClass m;
	cout << "[main] Before call Func" << endl;
	Func(m);
	cout << "[main] After call Func" << endl;
	cout << "[main] Before exit program" << endl;
	return 0;
}

The output result:
[main] Before declare m
[Constructor] Address of m_int: 006750E0
[main] Before call Func
[ViewInt] Value of m_int: 10
[Func] Within call Func
[Destructor] Address of m_int: 006750E0
[main] After call Func
[main] Before exit program
[Destructor] Address of m_int: 006750E0
—— CRASH ——-

OK, as we saw, there are somethings strange. The destructor of m was called twice times. The first time is in Func function, the second time is at the end of the main function.
I have some picture to illustrate whole progress:
First, when m is declared in main, the m_int is allocated in heap.
Image1_1
Next, when it’s passed to Func, a copied object of m will be created. This new object also have m_int field and this field also points to address of the old object m
Image1_2
When we exit the Func function, the copied object will be destroyed and its destructor will be called and delete the memory block at m_int pointed to
Image1_3
Before main function is exited, the m object will be destroyed and its destructor will be called and delete the memory block at m_int pointed to. But now, the block has already deleted before, so if we try to delete it again, we will have an error calledDangling pointer. On the other hand, we are trying to delete a memory block that we don’t have permission to do this. And of course, crashing will cause.
Image1_4

Solution:
In some cases, we want to perform passing a local object to other functions, and we know above way is actually wrong. Fortunately, we have another way to do this by passing the address of this object to other functions.

main.cpp

#include "MyClass.h"

#include

using namespace std;

void Func(MyClass *m) {
	m->ViewInt();
	cout << "[Func] Within call Func" << endl;
}

int main() {
	cout << "[main] Before declare m" << endl;
	MyClass m;
	cout << "[main] Before call Func" << endl;
	Func(&m);
	cout << "[main] After call Func" << endl;
	cout << "[main] Before exit program" << endl;
	return 0;
}

The output result:
[main] Before declare m
[Constructor] Address of m_int: 006750E0
[main] Before call Func
[ViewInt] Value of m_int: 10
[Func] Within call Func
[Destructor] Address of m_int: 006750E0
[main] After call Func
[main] Before exit program
[Destructor] Address of m_int: 006750E0

Now, let’s see what happens with m object
First, when m is declared in main, the m_int is allocated in heap.
Image1_1
Next, when it’s passed to Func by address, there is no copied object created, and we still use the old object to process
Image2_2
When we exit the Func function, because there is no object is created, so there is no object is destroyed, too.
Image2_3
Before main function is exited, the m object will be destroyed and its destructor will be called and delete the memory block at m_int pointed to. This is the first time this block is destroyed so everything is fine.
Image2_4

Another way for us to do this is passing by reference. The code will be here:
main.cpp

#include "MyClass.h"

#include

using namespace std;

void Func(MyClass &m) {
	m.ViewInt();
	cout << "[Func] Within call Func" << endl;
}

int main() {
	cout << "[main] Before declare m" << endl;
	MyClass m;
	cout << "[main] Before call Func" << endl;
	Func(m);
	cout << "[main] After call Func" << endl;
	cout << "[main] Before exit program" << endl;
	return 0;
}

The output result:
[main] Before declare m
[Constructor] Address of m_int: 006750E0
[main] Before call Func
[ViewInt] Value of m_int: 10
[Func] Within call Func
[Destructor] Address of m_int: 006750E0
[main] After call Func
[main] Before exit program
[Destructor] Address of m_int: 006750E0

Conclusion:
If you have to pass a local object to other functions, just remember to pass by address or reference to prevent the “Dangling pointer”

Advertisements

2 thoughts on “Never pass a local object to other functions by value”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s