Wednesday, August 30, 2017

What is copy constructor?

Copy constructor is used to copy instance.
We need to declare copy constructer when simple memory copying is undesirable.

For example, let's make variable length string class.

#include <iostream>
#include <string.h>

using namespace std;

class MyString
{
    char* str;
public:
    MyString() { str=nullptr; }
    ~MyString() { delete str; }

    void set(char const* src) {
        // delete existing memory and allocate enough new memory.
        delete str;
        str = new char[strlen(src)+1];    // danger code... don't care here.
        strcpy(str, src);
    }
    char* const get() {
        return str;
    }
};

void test(MyString copy_of_s)
{
    copy_of_s.set("abc"); // step 3
}

int main()
{
    MyString s;
    s.set("hello");    // step 1
    cout << s.get() << endl;   // output: hello
    test(s);           // step 2
    cout << s.get() << endl;   // step 4 -- what will be printed?
}

This class has no copy constructer yet.
What will happne on step 4??
Our program intend to print "hello". because test() takes a copy of MyString, so 's' will not be changed by the function.
But actually this program accesses dangling pointer on step 4.

Here describe the memory status step by step.

step 1 --- create MyString instance and set "hello".


step 2 --- copy instance by calling function


step 3 --- set "abc" to copied instance.


At this point, the memory storing string "hello" is deleted by MyString::set() funciton.
So at the step 4 MyString::get() function accesses the deleted memory.

To solve the problem, we should declare copy constructor.

class MyString
{
    char* str;
public:
    MyString() { str=nullptr; }
    ~MyString() { delete str; }

    // copy constructor.
    // take reference to source instance, allocate new memory and copy string holded by src.
    MyString(MyString const & src) {
        this->str = new char[strlen(src.str)+1];
        strcpy(this->str, src.str);
    }

    void set(char const* src) {
        // delete existing memory and allocate enough new memory.
        delete str;
        str = new char[strlen(src)+1];    // danger code... don't care here.
        strcpy(str, src);
    }
    char* const get() {
        return str;
    }
};

When calling test(), MyString(MyString const &src) is called.
Memory is managed properly, and say hello twice!



No comments:

Post a Comment

It&#39;s magic! std::bind

'std::bind' is a powerful helper for working around 'std::function'. 'std::bind' makes a instance of 'std::fun...