2011-01-10 58 views
3

考虑下面的代码:了解C++动态分配

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),因为它也是从主函数调用的,并将字符数组作为参数分配给堆中的参数......我怎样才能解决这个问题?

+0

你还需要在你的赋值运算符的工作(它不安全(喜欢复制和交换Idium))。见下文。 – 2011-01-10 20:59:00

回答

4

加法函数应该返回一个CString,而不是CString &。在添加函数中,应该构造返回值,然后删除[] 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; 
} 
+0

那么你在非静态方法中创建一个CString的新实例?我不认为这是一个很好的实现 – trojanfoe 2011-01-10 13:16:07

+2

@trojanfoe:这就是operator +通常被实现的方式。除了创建一个新的CString,你还会怎样返回一个CString? – Puppy 2011-01-10 13:17:11

+0

@DeMem非常感谢你!它毕竟简单,我应该做的就是创建对象而不立即返回,以便有时间删除数组! – kiokko89 2011-01-10 13:18:17

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

例如,

0

首先,operator+应该返回新的对象,而不是修改的+操作数之一,以更好地应被声明为一个非成员(可能是朋友)功能。首先执行operator+=,然后使用它 - operator+,你不会有这个问题。

CString operator+(CString const& lh, CString const& rh) 
{ 
    CString res(lh); 
    return res += rh; 
} 
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; 
} 

我们可以通过移动东西(并使用temp)来纠正这些问题。

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