0

我正在阅读推荐的 C++ 书籍之一,它建议在复制分配部分;

即使将对象分配给自身,赋值运算符也能正确工作,这一点至关重要。这样做的一个好方法是在销毁左手操作数之前复制右手操作数。

书中的例子;类有一个数据成员ps,并且ps is string *

C& operator=(const C &rhs)
{
     auto newp = new string(*rhs.ps)
     delete ps;
     ps = newp;
     return *this;        
}

但我们的教练建议

C& operator=(const C &rhs)
{
    if (this == &rhs)
        return *this;

     delete ps;
     ps = new string(*rhs.ps)
     return *this;  
}

导师的做法有问题吗?

4

6 回答 6

2

您可以使用以下范例来避免首先释放先前分配的资源,然后根据输入参数的属性重新分配它们的情况(否则会导致输入参数资源被释放的不良情况):

C& operator=(const C &rhs)
{
    if (this == &rhs)
        return *this;

    // For example:
    delete[] m_arr;
    m_len = rhs.m_len;
    m_arr = new int[m_len];
    for (int i=0; i<m_len; i++)
        m_arr[i] = rhs.m_arr[i];
}
于 2014-08-03T18:42:39.863 回答
2

存在代码无法编译的问题。代替

if (this == rhs.this)

必须有

if (this == &rhs)

否则没有问题。

于 2014-08-03T18:42:51.703 回答
2

这种方法有什么问题吗?

问题是它没有按照建议所说的那样做,无论如何它应该是

C& operator=( const C &rhs)
{
    if ( this == &rhs)
        return *this;

    // ...
}

可能最终的目标是写这样的东西:

C& operator=( C temp)
{
  Swap( temp );
  return *this;
}

有关此主题的更多信息,请参阅复制交换习语并查阅“Exceptional C++”。

于 2014-08-03T18:48:33.393 回答
2

你的导师的方法是有缺陷的。如果new string(*rhs.ps)失败,它将抛出一个异常,这将留下ps一个无效值(ps将是一个指向已删除内存的指针)。

new在删除旧数据之前,您必须确保已成功:

C& operator=(const C &rhs)
{
     auto new_ps = new string(*rhs.ps);
     delete ps;
     ps = new_ps;
     return *this;  
}

如果你愿意,你可以防止自赋值,但这不是必需的,而且由于自赋值不是很常见的情况,这样做可能会降低你的程序的性能。

请记住,如果您有自定义复制赋值运算符,您可能还需要自定义移动赋值运算符、复制构造函数、移动构造函数和析构函数。(见五法则)。

总的来说,这仍然是一个有缺陷的设计。ps应该只是一个string,或者应该是一个智能指针,例如value_ptr。手动管理内存既繁琐又容易出错。

于 2014-08-03T19:40:26.277 回答
0

一个简单的解决方案:使用std::unique_ptr

struct C {
    std::unique_ptr<std::string
    C& operator=(const C &rhs)
    {
        ps = new string(*rhs.ps)
        return *this;  
    }
};
于 2018-05-07T10:26:11.933 回答
-1

不,这种方法没有问题。

好吧,既然你编辑了它,那就有问题了。如果您想要好的建议,我建议您向人们提供完整的信息。

于 2014-08-03T18:36:06.967 回答