gpt4 book ai didi

C++ 运算符= return *this 后的结果发生变化

转载 作者:行者123 更新时间:2023-12-02 19:32:12 45 4
gpt4 key购买 nike

这里,我有一个非常简单的程序,将值从一个对象移动到另一个对象,并确保从获取值的对象中删除该值(留下“0”)。

#include <iostream>

struct S
{
S(char val) : m_val(val) {}
S& operator=(S&& other) noexcept
{
this->m_val = other.m_val;
other.m_val = '0';

return *this;
}
char m_val = '0';
};

int main()
{
S a('a');
S b('b');

std::cout << "a.m_val = '" << a.m_val << "'" << std::endl;
std::cout << "b.m_val = '" << b.m_val << "'" << std::endl;

a = std::move(b);

std::cout << "a.m_val = '" << a.m_val << "'" << std::endl;
std::cout << "b.m_val = '" << b.m_val << "'" << std::endl;

return 0;
}

正如预期的那样,该程序的输出是:

a.m_val = 'a'
b.m_val = 'b'
a.m_val = 'b'
b.m_val = '0'

“b”的值从对象 b 转移到对象 a,留下“0”。现在,如果我用一个模板(希望)自动执行移动和删除业务来进一步概括这一点,这就是我最终得到的结果......(当然是经过精炼的)。

#include <iostream>

template<typename T>
struct P
{
P<T>& operator=(P<T>&& other) noexcept
{
T& thisDerived = static_cast<T&>(*this);
T& otherDerived = static_cast<T&>(other);

thisDerived = otherDerived;
otherDerived.m_val = '0';

return *this;
}
protected:
P<T>& operator=(const P<T>& other) = default;
};

struct S : public P<S>
{
S(char val) : m_val(val) {}

char m_val = '0';
};

int main()
{
S a('a');
S b('b');

std::cout << "a.m_val = '" << a.m_val << "'" << std::endl;
std::cout << "b.m_val = '" << b.m_val << "'" << std::endl;

a = std::move(b);

std::cout << "a.m_val = '" << a.m_val << "'" << std::endl;
std::cout << "b.m_val = '" << b.m_val << "'" << std::endl;

return 0;
}

运行时,输出为:

a.m_val = 'a'
b.m_val = 'b'
a.m_val = '0'
b.m_val = '0'

呃哦!不知何故,两个对象都被“删除”了。当我单步执行移动赋值运算符代码的主体时......一切似乎都很好! a.m_val 是我们期望的“b”...直到 return *this; 语句。一旦它从函数返回,该值突然被设置回“0”。有人可以解释一下为什么会发生这种情况吗?

最佳答案

P<T>& operator=(P<T>&& other) noexcept

这是此模板类的显式移动赋值运算符。

struct S : public P<S> {

该子类继承自该模板类。 P<S>是它的父类。

这个子类没有显式的移动赋值运算符,因此您的 C++ 编译器会为您创建一个默认的移动赋值运算符,因为这就是 C++ 的工作方式。默认的移动赋值运算符调用父类的移动赋值运算符,然后默认的移动赋值运算符对此类的所有成员进行移动赋值。

仅仅因为父类有一个显式的移动赋值运算符(您的移动赋值运算符)并不会使这个子类的默认移动赋值运算符消失。 S的默认移动赋值运算符实际上是这样的,非常松散地说:

S &operator=(S &&other)
{
P<S>::operator=(std::move(other));
this->m_val=std::move(other.m_val);

return *this;
}

这就是您从 C++ 编译器中免费获得的内容。您的 C++ 编译器为您的类提供如此有用的默认移动赋值运算符不是很好吗?

a = std::move(b);

这实际上最终会调用上面的默认移动赋值运算符。

它首先调用父类的移动赋值运算符,即您编写的运算符。

这有效地设置了 other.m_val'0' .

当它返回时,这个默认的移动赋值运算符也会设置 this->m_val'0' .

关于C++ 运算符= return *this 后的结果发生变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60444696/

45 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com