Problem related to allocating memory

Hello,
Structure of my classes is as follows :

String.h
1
2
3
4
5
6
7
8
9
class String
{
   public:
          String();
          String(char*);
          ByteArray toByteArray();
   private:
           char* data;
};


String.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String::String(char* data)
{
	String::data=(char*)malloc(strlen(data)*sizeof(char));
	memcpy(String::data,data,strlen(data));
}

String::~String()
{
	free(data);
}

ByteArray String::toByteArray()
{
	ByteArray temp(7);  // returning ByteArray Object by value;
	return temp;
}


ByteArray.h
1
2
3
4
5
6
7
8
9
10
11
class ByteArray : public Object
{
	public:
			ByteArray(int NoOfElements);
			~ByteArray();
                        int length();
                        int8 valueAt(int);
	private:
			int8* data;   
			int datalength;
};


ByteArray.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ByteArray::ByteArray(int NoOfElements)
{
	data=(int8*)malloc(NoOfElements*sizeof(int8));
	datalength=NoOfElements;
	for(int i=0;i<datalength;i++)
		data[i]=0;
}

ByteArray::~ByteArray()
{
	free(data);
}

int ByteArray::length()
{
    return dataLength;
}

int8 ByteArray::valueAt(int index)
{
    return data[index];
}


Main.cpp
1
2
3
4
5
6
7
8
9
10
11
int main()
{
   String s("alpha");
   ByteArray b=s.toByteArray();  // getting ByteArray b by value
   for(int i=0;i<b.length();i++)
   {
      int8 temp=b.valueAt(i);
      SomeObject* so=new SomeObject();
   }
   return 0;
}


at line 4 of main() i get ByteArray object by value.
The ByteArray returned contains 7 elements all initialised to zero.

The for loop would traverse 7 times.
While traversing only the zero^th element returned by statement b.valueAt(i) is proper , rest all values are junk values as -77,-21...etc.

But when i remove statement SomeObject* so=new SomeObject();

i get proper values of object b.

==============

Then, i make when i changed the design as :-
instead of returning ByteArray by value i return it as a reference as :-

1
2
3
4
5
ByteArray* String::toByteArray()
{
	ByteArray* temp=new ByteArray(7);  // returning ByteArray Object by reference;
	return temp;
}


then in such a secanrio i don't get junk values...

I am not able to understand this concept.

why do i get junk values of elements of ByteArray object when returned by value and it works fine if i return ByteArray Object by reference.

help appreciated
amal


This is NOT really to do with pass by reference or pass by value.
This is all to do with the SCOPE of variables.

The following does not work because the temp array is a LOCAL variable to the ByteArray String::toByteArray() function.
Once the function finishes, the variable disappears and the address you
are returning for it will no longer be valid.
1
2
3
4
5
ByteArray String::toByteArray()
{
	ByteArray temp(7);  //array is local to this function
	return temp; //OOPS - returning the address of a local data
}


The next code works because the data array is now on the heap (created by using the new operator.)
Note that temp is a local variable and will vanish after the function finishes, but because we return it's value, we still know where the array data is located on the heap)

1
2
3
4
5
6
7
8
ByteArray* String::toByteArray()
{
    //temp pointer maybe a local variable, but the data it points to is created
    //on the heap - so it will not vanish when the function finishes.
    ByteArray* temp=new ByteArray(7);  

    return temp;
}
guestgulkan, the code
1
2
3
4
5
ByteArray String::toByteArray()
{
	ByteArray temp(7); 
	return temp; 
}

is quite correct. We all often return local variables and seldom have problems. See, you won't rail at this function
1
2
3
4
5
6
7
int sum(int a, int b)
{
   int sum;
   sum = a+b;
   return sum; //return local variable! In fact, its copy

}


Really the problem is that the ByteArray class do not provide a proper copy constructor and the compiler uses default copy constructor which is not proper in this case.

I'd suggest to add into the ByteArray class a copy constructor:
1
2
3
4
5
6
ByteArray::ByteArray(const ByteArray& b)
{
	datalength = b.datalength;
	data=(int8*)malloc(datalength*sizeof(int8));
	memcpy(data, b.data, dalalength*sizeof(int8));
}
Boy is my face red!
The original code said ByteArray temp(7);,
I mis-read it as ByteArray temp[7]; so I was on a trip thinking about arrays and away with the faries.

Sorry!
Last edited on
thnks melkiy,guestgulkan...that helped...

But how different is the copy constructor from a normal constructor.

Are copy constructors used only for such cases...

amal
You really should be using new and delete[] instead of malloc() and free()
A copy constructor for a class T is a constructor for T that has the signature:

 
T::T( const T& t )


and whose implementation must make a copy of its argument.

By default, the compiler gives you a copy constructor that does a member-wise copy. That is, given:

1
2
3
4
5
6
class T {
  int x;
  char y;
  float z;
  char* s;
};


the compiler will give you a copy constructor that does:

1
2
3
4
T::T( const T& t ) :
   x( t.x ), y( t.y ), z( t.z ), s( t.s )
{
}


(If you are not familiar with initializer list syntax, the line can be read as

1
2
x = t.x;
// etc 


Topic archived. No new replies allowed.