Operator =在C++中重载

Sad*_*que 11 c++ string operator-overloading visual-c++

在C++ Primer一书中,它有一个C风格字符数组的代码,并展示了如何=在第15.3Operator =中重载运算.

String& String::operator=( const char *sobj )
{
   // sobj is the null pointer,
   if ( ! sobj ) {
      _size = 0;
      delete[] _string;
      _string = 0;
   }
   else {
      _size = strlen( sobj );
      delete[] _string;
      _string = new char[ _size + 1 ];
      strcpy( _string, sobj );
   }
   return *this;
}
Run Code Online (Sandbox Code Playgroud)

现在我想知道为什么String &在下面的代码执行相同的工作时需要返回引用,没有任何问题:

void String::operator=( const char *sobj )
{
   // sobj is the null pointer,
   if ( ! sobj ) {
      _size = 0;
      delete[] _string;
      _string = 0;
   }
   else {
      _size = strlen( sobj );
      delete[] _string;
      _string = new char[ _size + 1 ];
      strcpy( _string, sobj );
   }

}
Run Code Online (Sandbox Code Playgroud)
  • 请帮忙.

Fre*_*Foo 20

它支持以下习语:

String a, b;
const char *c;

// set c to something interesting

a = b = c;
Run Code Online (Sandbox Code Playgroud)

为此,b = c必须返回适当的对象或引用来分配a; 它实际上是a = (b = c)根据C++运算符优先级规则.

如果你要返回指针this,你必须写a = *(b = c),这不会传达预期的含义.


Mat*_* M. 8

@larsmans已经回答了你的确切问题,所以我真的会离题:这是一些糟糕的代码!

这里的问题是3倍:

  1. 你只是复制了复制构造函数的代码(有点)
  2. strcpy可以更好地替换strncpy,它做一些绑定检查
  3. 这不是例外

1)和2)比任何东西都更具风格,但3)是一个大问题

编辑:正如@Jerry Coffin指出的那样,这并不能防止自我分配.那就是如果sobj并且_string指向相同的字符数组,那你就会遇到很大麻烦.本文末尾的简单解决方案也涵盖了这种情况.

也不例外

让我们看一下代码的else一部分,即部分:

  _size = strlen( sobj );
  delete[] _string;
  _string = new char[ _size + 1 ];
  strcpy( _string, sobj );
Run Code Online (Sandbox Code Playgroud)

如果出于某种原因new抛出什么会发生什么?

  • _size 具有新字符串的值
  • _string 指向旧指针......已被释放

因此,不仅对象处于不可用状态(其中一半数据来自新对象,一半来自旧对象),但它甚至无法销毁(除非析构函数泄漏......?)

添加异常安全,艰难的方式

  _size = strlen( sobj );
  delete[] _string;

  try {
    _string = new char[ _size + 1 ];
  } catch(...) {
    _size = 0; _string = 0;
    throw;
  }
  strcpy( _string, sobj );
Run Code Online (Sandbox Code Playgroud)

好吧,它真的是底线,但它给我们带来了基本的异常保证:没有功能保证,但保证代码在技术上是正确的(没有崩溃,没有泄漏).

添加异常安全,简单方法:Copy-And-Swap成语

在以下位置查找更完整的说明:什么是复制和交换习惯用法?

void swap(String& lhs, String& rhs) {
  using std::swap;
  swap(lhs._size, rhs._size);
  swap(lhs._string, rhs._string);
}

String& String::operator=(String other) { // pass-by-value
  swap(*this, other);
  return *this;
}
Run Code Online (Sandbox Code Playgroud)

它是如何工作的 ?

  • 我们重复使用复制构造函数来实现副本
  • 我们重用交换函数来交换值
  • 我们重复使用析构函数进行清理

它甚至比以前的版本更好,因为现在我们有强异常保证:它是事务性的,因此如果失败,我们分配给的字符串不变(好像什么也没发生).

更多关于例外保证.

我有点沮丧,C++教程会推广这些可疑的代码,请告诉我这是一个不该做的例子:/