[Post] copying a class containing pointer members

Source: Internet
Author: User

From: http://zhedahht.blog.163.com/blog/static/25411174200722710364233/

Question: The following is an array class declaration and implementation. Analyze the problems in this category and propose several solutions to the problems.

template<typename T> class Array
{
public:
Array(unsigned arraySize):data(0), size(arraySize) {
if(size > 0)
data = new T[size];
}
~Array() {
if(data)
delete[] data;
}
void setValue(unsigned index, const T& value) {
if(index < size)
data[index] = value;
}
T getValue(unsigned index) const {
if(index < size)
return data[index];
else
return T();
}
private:
T* data;
unsigned size;
};

 

Analysis: We note that pointers used to store array data are encapsulated in the class. Most of the software's problems can usually be caused by incorrect pointer processing. This class only provides one constructor without defining the constructor and the reload copy operator. When the user of this class declares and instantiates an instance of this class according to the following method:

Array A(10);
Array B(A);

Or assign an instance of this class to another instance as follows:

 

Array A(10);
Array B(10);
B=A;

 

The compiler calls the automatically generated constructor or the reload function of the copy operator. In the default constructor generated by the compiler to construct the copy function and the copy operator to overload the function, the pointer is implemented by bitwise copy, just copying the pointer address, instead of copying the pointer content. Therefore, after executing the preceding code, A. Data and B. data point to the same address. When any one of A or B calls the destructor to end its lifecycle, data is deleted. Because their data points to the same place, the data of both instances is deleted. But another instance does not know that its data has been deleted. When trying to use its data again, the program will inevitably crash.

 

The root cause of the problem is that the default constructor generated by the compiler and the reload function of the copy operator are called. One of the simplest ways is to disable these two functions, so we can declare these two functions as private functions. If the class user attempts to call these two functions, they will not be compiled. The implementation code is as follows:

private:
Array(const Array& copy);
const Array& operator = (const Array& copy);

 

The original code has a problem because the data of different instances points to the same address. Deleting the data of one instance also deletes the data of another instance. Therefore, we can also make a copy function or an overload function of the copy operator copy data instead of an address. Because we re-store a copy of data, such an instance is deleted without affecting another instance. This idea is called Deep copy. The implementation code is as follows:

public:
Array(const Array& copy):data(0), size(copy.size) {
if(size > 0) {
data = new T[size];
for(int i = 0; i < size; ++ i)
setValue(i, copy.getValue(i));
}
}

Array& operator = (const Array& copy) {
if(this == &copy)
return *this;
if(data != NULL) {
delete []data;
data = NULL;
}
size = copy.size;
if(size > 0) {
data = new T[size];
for(int i = 0; i < size; ++ i)
setValue(i, copy.getValue(i));
}
}

 

To prevent data directed by multiple pointers from being deleted multiple times, we can also save the number of pointers pointing to the data. It can be deleted only when no pointer points to the data. This idea is often referred to as the reference counting technology. In the constructor, the reference count is initialized to 1. When this instance is assigned to another instance or the constructor that passes parameters to other instances, the reference count is incremented by 1, this means that another instance points to its data. Each time you need to call the Destructor or assign data to another data, the reference count is reduced by 1, this means that the pointer to data is missing. When the reference count is reduced to 0, data is no longer directed to any instance, and can be safely deleted. The implementation code is as follows:

 

public:
Array(unsigned arraySize) :data(0), size(arraySize), count(new unsigned int) {
*count = 1;
if(size > 0)
data = new T[size];
}
Array(const Array& copy) : size(copy.size), data(copy.data), count(copy.count) {
++ (*count);
}
~Array() { Release(); }
const Array& operator = (const Array& copy) {
if(data == copy.data)
return *this;

Release();

data = copy.data;
size = copy.size;
count = copy.count;
++(*count);
}

private:
void Release() {
--(*count);
if(*count == 0) {
if(data) {
delete []data;
data = NULL;
}

delete count;
count = 0;
}
}

unsigned int *count;

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.