默认的赋值运算符会检查是否进行了自我赋值操作。

7
我想知道赋值运算符的默认实现是否检查自我赋值,因此哪个实现可以被认为是最接近默认的实现:
class A{
    int x;
public :
    ...
    // first one
    A& operator=(const A& a){
        if(this != &a) x = a.x;
        return *this;
    }
    // second one
    A& operator=(const A& a){
        x = a.x;
        return *this;
    }
}

我搜索了C++标准,但我找到的唯一一个是这个,但里面没有任何相关信息。
2个回答

5
不,实现不会检查“self”:

https://en.wikipedia.org/wiki/Assignment_operator_(C%2B%2B)

复制赋值运算符通常称为“赋值运算符”,是一种特殊的赋值运算符,其中源(右侧)和目标(左侧)属于相同的类类型。

它是特殊成员函数之一,这意味着如果程序员没有声明它,则编译器会自动生成默认版本。

默认版本执行“按成员复制”,其中每个成员都由其自己的复制赋值运算符进行复制(也可以是程序员声明或编译器生成的)。


2
该描述并不排除默认生成的实现执行自我赋值检查的可能性。标准并未阻止这种情况。唯一确定的方法是实际查看编译器生成的代码。 - Remy Lebeau
2
@RemyLebeau 标准规定:“对于非联合类 X,其隐式定义的复制/移动赋值运算符执行其子对象的逐成员复制/移动赋值。”这如何允许实现检查自我赋值? - 1201ProgramAlarm
1
@Remylebeau 什么是成员的自我赋值具有可观察效果?那么它就不能被省略。 - 463035818_is_not_a_number
@463035818_is_not_a_number编译器无法知道任何给定成员是否存在这样的副作用。这样的副作用需要该成员为自身实现赋值运算符,而编译器不会查看该运算符的实现以了解其功能。 - Remy Lebeau
@RemyLebeau 是的,那也是我的想法,因此我认为不允许优化掉自我赋值,因为这可能会产生可观察到的差异。 - 463035818_is_not_a_number
显示剩余2条评论

3

赋值运算符不会检查自我赋值。因此,你的第二个实现是最接近默认实现的。

我在标准中没有看到任何关于这种优化的字眼。如果我的类属性在某些情况下没有被编译器生成的运算符分配,那将是奇怪的。想象一下,某些属性分配是用户定义的,并执行一些不寻常的任务。编译器并不知道这一点,我认为即使我将对象分配给自身,它也应该调用它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接