Understanding C ++ Dynamic Distribution

Consider the following code:

class CString
{
private:
    char* buff;
    size_t len;

public:
    CString(const char* p):len(0), buff(nullptr)
    {
        cout << "Constructor called!"<<endl;
        if (p!=nullptr)
        {
            len= strlen(p);
            if (len>0)
            {
                buff= new char[len+1];
                strcpy_s(buff, len+1, p);               
            }           
        }       
    }

    CString (const CString& s)
    {
        cout << "Copy constructor called!"<<endl;
        len= s.len;
        buff= new char[len+1];
        strcpy_s(buff, len+1, s.buff);      
    }

    CString& operator = (const CString& rhs)
    {
        cout << "Assignment operator called!"<<endl;
        if (this != &rhs)
        {
            len= rhs.len;
            delete[] buff;          
            buff= new char[len+1];
            strcpy_s(buff, len+1, rhs.buff);
        }

        return *this;
    }

    CString operator + (const CString& rhs) const
    {
        cout << "Addition operator called!"<<endl;

        size_t lenght= len+rhs.len+1;
        char* tmp = new char[lenght];
        strcpy_s(tmp, lenght, buff);
        strcat_s(tmp, lenght, rhs.buff);

        return CString(tmp);
    }

    ~CString()
    {
        cout << "Destructor called!"<<endl;
        delete[] buff;
    }     
};

int main()
{
CString s1("Hello");
CString s2("World");
CString s3 = s1+s2;     
}

My problem is that I do not know how to remove the memory allocated in the function of the addition operator ( char* tmp = new char[length]). I could not do this in the constructor (I tried delete[] p) because it is also called from the main function with arrays of characters as parameters that are not allocated on the heap ... How can I get around this?

+3
source share
4 answers

The add function should return a CString, not a CString &. In the add function, you must build the return value and then remove the [] temp, since it is no longer needed, since a copy of the memory is created inside the CString class.

CString operator + (const CString& rhs) const
{
    cout << "Addition operator called!"<<endl;

    size_t lenght= len+rhs.len+1;
    char* tmp = new char[lenght];
    strcpy_s(tmp, lenght, buff);
    strcat_s(tmp, lenght, rhs.buff);

    CString retval(tmp);
    delete[] tmp;
    return retval;
}
+4
source

Problems:

. , , . - , undefined.

CString& operator = (const CString& rhs)
{
    cout << "Assignment operator called!"<<endl;
    if (this != &rhs)
    {
        len= rhs.len;
        delete[] buff;          
        buff= new char[len+1];   /// BOOM 

        // If you throw here buff now points at undefined memory.
        // If this is an automatic variable the destructor is still going
        // to be called and you will get a double delete.

        // All operations that can fail should be done BEFORE the object is modified.

        strcpy_s(buff, len+1, rhs.buff);
    }

    return *this;
}

, ( ).

CString& operator = (const CString& rhs)
{
    cout << "Assignment operator called!"<<endl;
    if (this != &rhs)
    {
        char* tmp = new char[len+1];
        strcpy_s(tmp, rhs.len+1, rhs.buff); // for char this will never fail
                                            // But if it was another type the copy
                                            // may potentially fail. So you must
                                            // do the copy before changing the curren
                                            // objects state.

        // Now we can change the state of the object safely.
        len= rhs.len;
        std::swap(tmp,buff);

        delete tmp;
    }

    return *this;
}

idium:

CString& operator = (CString rhs) // Note pass by value to get auto copy.
{                                 // Most compilers will then do NRVO
    this->swap(rhs);
    // Simply swap the tmp rhs with this.
    // Note that tmp was created with copy constructor.
    // When rhs goes out of scope it will delete the object.
}

void swap(CString& rhs)
{
    std::swap(len,  rhs.len);
    std::swap(buff, rhs.buff);
}

+

CString operator + (const CString& rhs) const
{
    // You could optimize this by providing a private constructor
    // that takes two char pointers so that allocation is only done
    // once.
    CString result(*this);
    return result += rhs;
}

CString operator += (const CString& rhs)
{
    size_t lenght= len+rhs.len+1;

    // Char are easy. No chance of failure.
    // But if this was a type with a copy constructor or any other complex
    // processing involved in the copy then I would make tmp a smart pointer
    // to make sure that it memory was not leaked if there was an exception.
    char* tmp = new char[lenght];

    strcpy_s(tmp, lenght, buff);
    strcat_s(tmp, lenght, rhs.buff);

    std::swap(len, length);
    std::swap(buff, tmp);

    delete tmp;
}
+2
    CString& operator + (const CString& rhs) const

{
    cout << "Addition operator called!"<<endl;

    size_t lenght= len+rhs.len+1;
    char* tmp = new char[lenght];
    strcpy_s(tmp, lenght, buff);
    strcat_s(tmp, lenght, rhs.buff);
    CString tempObj(tmp);
    delete [] tmp;
    return tempObj;
}

,

0

, operator+ , +, , (, ). operator+=, - operator+, .

CString operator+(CString const& lh, CString const& rh)
{
    CString res(lh);
    return res += rh;
}
0

Source: https://habr.com/ru/post/1784525/


All Articles