首页 > 编程知识 正文

c语言算术运算符,c语言赋值运算符号是什么

时间:2023-05-04 02:54:18 阅读:163273 作者:2853

类的赋值运算符允许使用=将一个实例分配给另一个实例。 例如:

MyClass c1,c2;

c1=c2; //assigns c2 to c1

实际上,赋值运算符的函数签名有几种。

)1) my class operator=(constmyclassrhs );

)2) myclassoperator=(myclassRHS );

)3) myclassoperator=(myclassRHS );

)4) constmyclassoperator=(constmyclassrhs );

)5) constmyclassoperator=(my class RHS );

)6) constmyclassoperator=(我的类别RHS );

)7) my class operator=(constmyclassrhs );

)8) myclassoperator=(myclassRHS );

(9) myclassoperator=) myclassRHS;

注意: rhs表示right-hand side,运算符右侧的对象。

这些签名在返回类型和参数类型上存在差异。

返回类型可能不重要,但选择参数类型很重要。

(2,) 5和(8)以非const引用方式传递参数。

不推荐使用这种方法。 这些签名的问题是以下代码无法编译。

我的类别C1;

C1=myclass(5,' a ',' Hello World ' ); //assumingthisconstructorexists

这如上述复制构造函数所述,暂时的对象制作无法通过非常参照的方式传达。

这是因为此赋值表达式的右侧是临时(未命名)对象,而C标准禁止编译器通过非静态引用参数传递临时对象。

这样,只能通过值或常量引用传递右侧的对象。

通过常量引用进行引用传递可能比通过值传递更有效,但出于异常的安全原因,创建源对象的临时副本是不可避免的。 此外,通过传递值还可以减少代码的行数。

什么时候需要写一个赋值运算符函数?

首先,必须知道,如果没有声明赋值运算符,编译器将隐式生成。

此隐式赋值运算符将值赋给源对象的每个数据成员,就像复制构造函数一样。

例如,如果使用上面的类,编译器提供的赋值运算符函数与以下内容完全相同:

我的类别我的类别:3360操作者={ constmyclassother }

x=other.x;

c=other.c;

s=other.s;

return *this;

}

通常,如果需要编写自己的自定义复制构造函数,还必须编写自定义赋值运算符。 通常,如果成员变量包含原始指针,并且需要深度复制。

所以复制构造函数和赋值构造函数关系密切,就像双胞胎一样。

请注意,默认复制构造函数为每个成员调用复制构造函数,而赋值操作符为每个成员调用赋值操作符。

异常安全的代码是什么意思?

在此插入关于异常安全的插曲。 因为程序员们经常误以为异常处理是异常安全的。

修正了一些“全局”状态的函数(

参数或更改该实例的数据成员的成员函数)称为异常安全。

实例的成员函数),如果在异常发生时能够很好地定义全局状态,可以说是异常安全的。

只要能正确定义全局状态,函数中任意时刻抛出的异常就称为异常安全。

这到底是什么意思? 那么,举个相当牵强(旧)的例子吧。 此类包装具有用户指定数据类型的数组。 有两个数据成员:指向数组的指针和数组中的元素。

templatetypenametclassmyarray { size _ tnum elements; T*pElements; public:size_t count () const { return n

umElements; }      MyArray& operator=( const MyArray& rhs );  };

上面这是一个模板类,那么,给这个模板类定义一个赋值运算符:

template<>  MyArray<T>::operator=( const MyArray& rhs ) {      if( this != &rhs ) {          delete [] pElements;          pElements = new T[ rhs.numElements ];          for( size_t i = 0; i < rhs.numElements; ++i )              pElements[ i ] = rhs.pElements[ i ];          numElements = rhs.numElements;      }      return *this;  }

但这行代码可能有问题:

pElements[ i ] = rhs.pElements[ i ];

这行代码可能会抛出一个异常。

这一行对类型T调用了operator=,这个类型可能是一些用户定义的类型,其赋值运算符可能会抛出一个异常,也许是内存不足(std::bad_alloc)的异常,或其他用户定义的类型的程序员创造的异常。

如果它真的抛出,例如在复制10的第3个元素时,会发生什么?

好吧,函数调用栈返回,直到找到一个合适的处理程序。

同时,我们的对象的状态是什么?嗯,我们重新分配了我们的数组来容纳10个T,但是我们只成功复制了其中的两个。第三个失败了,剩下的七个甚至没有被尝试过被复制。此外,我们甚至没有改变numElements,所以它还是原来的元素个数。很明显,如果我们在这个时候调用 count() 返回元素个数,返回的数字是不对的。

但显然,MyArray的程序员从来没有想过让count()给出一个错误的答案。更糟糕的是,可能还有其他成员函数更加依赖numElements的正确性(甚至达到崩溃的程度)。

这个例子显然是一个等待爆炸的定时炸弹。

这个operator=的实现不是异常安全的:如果在函数的执行过程中出现了异常抛出,我们就无法知道对象的状态是什么。

我们只能假设它处于这样一种糟糕的状态(即它违反了它自己的一些不变性),以至于无法使用。如果该对象是处于不良状态,甚至不可能在不破坏程序的情况下销毁该对象或导致MyArray抛出另一个异常。

我们知道,编译器在运行析构器的同时会返回栈以寻找一个处理程序。如果在返回栈时抛出了一个异常。程序必然会不可阻挡地终止。

如何编写一个异常安全的赋值运算符?

推荐的方法是通过以下方式来写一个异常安全的赋值运算符复制-交换模式。什么是copy-swap模式?简单地说,它是一种两步骤的算法:首先制作一个副本,然后与副本进行交换。下面是我们的异常安全版本的operator=。

  template<>  MyArray<T>::operator=( const MyArray& rhs ) {      // First, make a copy of the right-hand side      MyArray tmp( rhs );      // Now, swap the data members with the temporary:      std::swap( numElements, tmp.numElements );      std::swap( pElements, tmp.pElements );      return *this;  }

注意,这里是要对每个成员进行std::swap,指针类型也可以交换成功。

但如果这里改成:

std::swap(tmp, *this);

那就会变成无线递归调用,直到程序异常后停止执行。

因为你这里定义的是赋值操作符,而swap里,也会调用到这个对象的赋值操作,如果直接传入自己的对象,虽然编译没问题,但执行的时候,就会变成递归调用了。

异常处理和异常安全之间的区别的重要性就在这里:我们并没有阻止异常的发生;事实上。

从rhs到tmp使用拷贝构造函数时就可能会发生,因为它将复制T的内容。

但是,如果复制结构确实抛出异常,注意*this的状态并没有改变,这意味着在异常发生时,我们可以保证

我们可以保证*this仍然是正常的,此外,我们甚至可以说,它保持不变。

但是,你说,那std::swap呢?它能不抛出吗?是的,也不是。默认的std::swap<>,定义在<algorithm>中,可以抛出,因为std::swap<>看起来像这样:

template< typename T >  swap( T& one, T& two )  {      T tmp( one );      one = two;      two = tmp;  }

第一行运行T的复制构造函数,它可以抛出;其余几行是赋值运算符,也可以抛出。

然而,如果你有一个类型T,使用默认的std::swap()可能导致T的复制构造函数或赋值运算符抛出异常,那么你就需要为你的类型提供一个不抛出的 swap() 重载。

因为swap()不能返回失败,而且你也不允许抛出异常。

你的swap()重载必须总是成功。 通过要求swap不抛出异常,上面的operator=是安全的:要么对象被完全复制成功,或者左手边的对象保持不变。

现在你会注意到,我们对operator=的实现在第一行代码中就做了一个临时拷贝。既然我们必须做一个拷贝,我们不妨让编译器自动完成,这样我们就可以修改函数的签名,以便通过值(即拷贝)而不是引用来获取右边的内容。而不是通过引用,这样我们就可以省去一行代码。

template<>  MyArray<T>::operator=( MyArray tmp ) {      std::swap( numElements, tmp.numElements );      std::swap( pElements, tmp.pElements );      return *this;  }

参考:

Copy constructors, assignment operators, - C++ Articleshttp://www.cplusplus.com/articles/y8hv0pDG/

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。