了解C ++动态分配

时间:2011-01-10 13:01:20

标签: c++ dynamic allocation delete-operator

请考虑以下代码:

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;     
}

我的问题是我不知道如何删除在加法运算符函数(char* tmp = new char[length])中分配的内存。我无法在构造函数中执行此操作(我尝试delete[] p),因为它也是从main函数调用的,其中chars数组作为参数未在堆上分配...我如何解决这个问题?

4 个答案:

答案 0 :(得分:4)

添加函数应返回CString,而不是CString&amp;。在添加函数中,你应该构造返回值,然后删除不再需要的[] temp,因为在CString类中你可以创建一个内存副本。

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;
}

答案 1 :(得分:2)

问题:

在您的赋值运算符中,您未能提供任何异常保证。在确保操作成功之前,您正在删除缓冲区。如果出现问题,您的对象将处于未定义状态。

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's 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 :(得分:0)

    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;
}

例如,

答案 3 :(得分:0)

首先,operator+应返回新对象,而不是修改+的操作数之一,因此最好将其声明为非成员(可能是朋友)函数。首先实现operator+=然后使用它 - operator+,你就不会遇到这个问题。

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