Does Copy Constructor require explicit copy statements for each class members?

I have below code where I have a class with an array which is created by a pointer and another simple integer value.
Since I am creating the int array with a pointer, thus I need to implement a copy constructor to handle the pointer copy when I assign one object of the class to another.

Here is the class declaration:
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
class array {

    private:
        int *p;
        int size;

    public:
        array(int len) {
            p = new(nothrow) int[len];
            if(p != nullptr)
                size = len;
            else
            {
             cout<<"Allocation failure";
             exit(EXIT_FAILURE);   
            }
        }

        array(array &a);         //copy constructor

        void put(int i, int j) { if(i>=0 && i<size)  p[i]=j;}

        int get(int i) { 
            if(i>=0 && i<size) return p[i];   
            else return -1;
        }

        ~array() {          
            cout<<"destrying..."<<endl;
            delete [] p;
        }

};


Then I implement the copy constructor like below where I manually implement the memory allocation of the array in the new object:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
array :: array( array &a)
{
    int i;
    p = new(nothrow) int[a.size];
    if(p == nullptr)
    {
        cout<<"Allocation failure"<<endl;
        exit(EXIT_FAILURE);
    }
    for(i=0; i<a.size; i++)
    p[i]=a.p[i];

    //why explicitly writing this line is necessary?
    //size = a.size;
}


However, as mentioned in the commented line, as long as i explicitly don't copy the "size" variable, c++ doesn't automatically copy the value from old object to new object.
Example, below is how I call them from main:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main()
{
    array num(10); //create a 10 size array
    
    for(int i=0; i<10; i++) // assign 10 values into it
        num.put(i, i);

    for(int i=0; i<10; i++) // print the values of num
        cout<<num.get(i)<<endl;
    
// creating a new array type object named "X" where 
// values from obj "num" being copied

    array x(num); 

    for(int j=0; j<10; j++) //print values of X obj
        cout<<x.get(j)<<endl;

    return 0;
}



Here the statement array x(num) leads to properly copying all values of p from num to x.
But as long as I don't explicitly write size = a.size inside the copy constructor, variable size inside x gets 0, not 10.

Does it mean that if I implement a copy constructor, then I have to manually handle copying each member from source object to destination object?

I tried to google the problem, but may be my keywords weren't good enough so I didn't get a satisfactory answer to my question. Assuming this is a trivial question, I appreciate if anyone links any existing thread which addresses my question.
Thanks in advance.
Last edited on
Does it mean that if I implement a copy constructor, then I have to manually handle copying each member from source object to destination object?

Yes! I think a copy constructor of your array class would have to:

1. Set size of the "new" object to the same value as size in the "original" object

2. Allocate for the "new" object a new p array, of the same size as the array of the "original" object's p array

3. memcpy() all data from the "original" object's p array to the "new" object's p array
Last edited on
Thanks.
I did it for int *p member of class array.
But my confusion was regarding the int size. As long as I didn't explicitly copied the value, it got value 0.

So does it mean that this needs to be done for each class members and c++ will not automatically do anything unless the coder explicitly writes the code inside the copy constructor method?
I am following H. Schildt's C++ Complete Refrence book 4th edition. But the book doesn't explain this.
Yes, if you implement an explicit copy constructor, then it is your responsibility to make the "new" object an exact copy of the "original" object. This means that you have to properly initialize all fields of the "new" object, just as you would have to in a "normal" constructor. Except that, in the copy constructor, you take the values from the "original" object. As far as the p array is concerned, you need to do a "deep copy", i.e. allocate a new[] array of appropriate size for the "new" object and then memcpy() all data from the "original" array.
Last edited on
Great answer! :) Thank you very much. Marking as solved.
Assuming your array class has a fixed size (i.e. no "resize" support is planned), then I suggest:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class array {
private:
    int *const p;
    const size_t size;
public:
    array(const size_t len) : size(len), p(new int[len])
    {
        memset(p, 0, sizeof(int) * len);
    }
    array(const array &a) : size(a.size), p(new int[a.size])
    {
        memcpy(p, a.p, sizeof(int) * a.size);
    }
    /* ... */
}



Also, there is no need to check the result of the new[] operator for a null value!

Unlike the malloc() function in C, the new[] operator in C++ doesn't return null in case of error, but throws an exception instead! Finally, don't call exit() from a constructor; let the caller handle possible exceptions!

BTW: Better use the size_t type for any variables holding a "size" value.
https://www.cplusplus.com/reference/cstring/size_t/

BTW²: Using memcpy() or std::copy() probably is faster than copying element-by-element in a loop.
Last edited on
new[] (or new) doesn't return nullptr by default in case of error, but can if you use:

 
new(std::nothrow) ...


which won't throw on error but return nullptr.
Topic archived. No new replies allowed.