Why wouldnt this work???

Pages: 12
The Following in my book:

"
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
// Ex7_09.cpp
// Initializing an object with an object of the same class
#include <iostream>
using std::cout;
using std::endl;

class CBox                             // Class definition at global scope
{
  public:
    // Constructor definition
    explicit CBox(double lv = 1.0, double bv = 1.0, double hv = 1.0)
    {
      cout << endl << "Constructor called.";
      m_Length = lv;                   // Set values of
      m_Width = bv;                    // data members
      m_Height = hv;
    }

    // Function to calculate the volume of a box
    double Volume()
    {
      return m_Length*m_Width*m_Height;
    }

  private:
    double m_Length;                   // Length of a box in inches
    double m_Width;                    // Width of a box in inches
    double m_Height;                   // Height of a box in inches
};

int main()
{
   CBox box1(78.0, 24.0, 18.0);
   CBox box2 = box1;                   // Initialize box2 with box1

   cout << endl
        << "box1 volume = " << box1.Volume()
        << endl
        << "box2 volume = " << box2.Volume();

   cout << endl;
   return 0;
}


This example produces the following output:

Constructor called.
box1 volume = 33696
box2 volume = 33696


How It Works

The program is working as you would want, with both boxes having the same volume. However, as you can see from the output, our constructor was called only once for the creation of box1. The question is, how was box2 created? The mechanism is similar to the one that you experienced when you had no constructor defined and the compiler supplied a default constructor to allow an object to be created. In this instance, the compiler generates a default version of what is referred to as a copy constructor.

A copy constructor does exactly what we’re doing here — it creates an object of a class by initializing it with the values of the data members of an existing object of the same type. The default version of the copy constructor creates a new object by copying the existing object, member by member.

This is fine for simple classes such as CBox, but for many classes — classes that have pointers or arrays as members, for example — it won’t work properly. Indeed, with such classes the default copy constructor can create serious errors in your program. In these cases, you must create your own copy constructor. This
requires a special approach that you’ll look into more fully toward the end of this chapter and again in the next chapter.
"

I have a question about this sentence in the last paragraph:

"This is fine for simple classes such as CBox, but for many classes — classes that have pointers or arrays as members, for example — it won’t work properly."

Why wont it work properly for arrays or pointers as members? Can someone please shed some light on this for me?
Last edited on
An array declared as int blah[], or even int* blah = malloc(blah blah blah) are both just pointers to an address in memory. An array isn't a struct or a class and there is nothing defining boundaries for it. Therefore when you want to copy an array, you must do it iteratively for each element.
Ohhh good point. So when you do that you only copy the address of the array and not the whole array itself?
Correct. Because an array is just contiguous memory. That is why you can easily go out of range corrupt memory.

Pointer however do copy

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
class pointer
{
	int* x;

public:
	pointer(int _x)
	{
		x = new int;
		*x = _x;
	}
	void show()
	{
		std::cout << *x << " : " << x << std::endl;
	}
};

int main()
{
	pointer y(5);
	pointer v = y;

	y.show();
	v.show();

        return 0;
}



5 : 0x895010
5 : 0x895010
So then what is the problem with pointers or is there none?
Wait then how does the range based for loop work if the array doesn't know its boundaries? Or does the compiler know them?
1) Copying pointer like in the code, albeit dangerous, works just fine.


2) what do you mean?

When you loop,
1
2
3
4
5
6
7
8
9
10
11

int array[10];

//This fills all the array slots with 7, notice I told it specifically to only do 10 indexes
for(int i = 0; i < 10; ++i )
  array[i] = 7;

//However, this is also valid but will possibly corrupt 990 x sizeof(int) bytes of memory.
for(int i = 0; i < 1000; ++i )
  array[i] = 7;
A range Based for loop. That automatically knows where the array ends and goes through it. Its part of c++ 11.

Why is copying a pointer dangerous?
In regards to the dangerous part

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
class pointer
{
	int* x;

public:
	pointer(int _x)
	{
		x = new int;
		*x = _x;
	}
	void setx(int _x)
	{
		*x = _x;
	}
	void show()
	{
		std::cout << *x << " : " << x << std::endl;
	}
};

int main()
{
	pointer y(5);
	pointer v = y;

	y.show();
	v.show();

	v.setx(7);

	y.show();
	v.show();

return 0;
}



5 : 0x1ceb010
5 : 0x1ceb010
7 : 0x1ceb010
7 : 0x1ceb010


As you can see, x in both classes points to the same location in memory. If you intend to share memory that might be ok as long as both classes are not accessing it at the same time. But if this is not your intention then you can get lots of unexpected results
Oh ok. But then can you also explain how a range based for loop works if an array doesnt store its size? Does the compiler know or what?

A range based for loop looks like this:

1
2
3
4
int array 10

for (int i:array)
{blah blah}


it loops until it reaches the end of the array. How does this work?
Last edited on
I am still unfamiliar with c++11, you will just have to read the documentation.
Last edited on
Aww ok.

Just to clear up There is absolutely no reason other than its dangerous for pointers right?
http://en.cppreference.com/w/cpp/container/array

it is a class, therefore it has built in functionality
Ok found this:

Information regarding the size of an array is pushed onto the program's stack followed by the array itself. This assumption is confirmed with the following code:

1
2
int Array[5];
std::cout << sizeof( Array );


The above code will output 5. If the compiler did not keep track of the array's size, "sizeof" would yield some undefined value or even an error.

Though, in some circumstances, "sizeof" does yield a value, but a value that's unexpected. For instance:


1
2
3
4
void Function( int Array[] )
{
  std::cout << sizeof( Array );
}


One could assume that the "Array" parameter is an array, but they'd be wrong because "Array" is a pointer, and in C++, pointers always consume the same amount of memory. Common outputs for "sizeof" in the above code would be either 4- or 8-bytes.

If the compiler knows the length of the array, why can't I retrieve the size of the array with "sizeof" in the above code?

Because "Array" is a pointer, the compiler cannot assume that the address pointed-to by the pointer is an element of an array. Just because the declaration of "Array" looks like a declaration of an array, you can't assume that "Array" refers to an array. Remember: a pointer can point to any piece of storage so long as the storage has the same type as the pointer's type-identifier. For example:


int *Pointer;

Here, "Pointer" can point to any "int" storage, regardless of whether the storage is associated with an array, class or name-space.


Thanks
Last edited on

Anmol444 (196) Apr 15, 2013 at 6:25pm
Aww ok.

Just to clear up There is absolutely no reason other than its dangerous for pointers right?


Yeah.
Awesome :D
But wait isnt it still working properly? So why would the author say it isnt working properly.. hmmm.
cool. I didn't know that sizeof(arrayvariable) worked.

The above code will output 5. If the compiler did not keep track of the array's size, "sizeof" would yield some undefined value or even an error.

No it will print 5 * sizeof(int), sizeof(Array)/sizeof(Array[0]) will print 5.

http://ideone.com/UOCapW
Pages: 12