*this = Foo(); 恢复类不变式:合法性与效率技术问询
关于C++中
*this = Foo();的合法性与效率分析 先来看你提到的这段用于重置类状态的代码:
class Foo { // some stuff in here public: void clear() { *this = Foo(); //operator=(Foo()); // commented out in favor of the line above } };
你对这段代码的思考很有道理,下面我来逐个解答你的问题:
1. 语句*this = Foo();是否合法?
完全合法!我们可以从C++标准的核心规则来验证:
*this在非const成员函数中是Foo&类型的左值,代表当前已存在的对象;Foo()是一个临时的右值对象,由默认构造函数构造。- 赋值运算符(无论是编译器默认生成的还是自定义的)的设计就是用来修改已有对象的状态:默认的复制赋值运算符接受
const Foo&参数,能兼容临时对象;如果类支持移动语义,默认的移动赋值运算符会接受Foo&&参数,更高效地处理右值。 - 根据C++标准对赋值表达式的定义:赋值操作的左操作数必须是可修改的左值,
*this完全满足;右操作数可以是任意能转换为左操作数类型的表达式,临时Foo对象显然符合要求。
2. 不同场景下的效率对比
(1)当Foo类可移动时
这种场景下*this = Foo()的效率非常出色:
- 临时对象
Foo()是右值,会触发移动赋值运算符。移动操作本质是转移内部资源的所有权(比如动态分配的内存、容器的缓冲区),几乎没有内存拷贝的开销,性能接近手动重置成员的最优情况。 - 而且编译器通常会对临时对象进行优化,比如省略不必要的临时对象构造步骤,进一步降低开销。
- 更重要的是,这种写法的维护性远高于手动赋值——后续给
Foo添加新成员时,不需要修改clear函数,就能自动重置新成员的状态,避免遗漏。
(2)当Foo类不可移动时
此时*this = Foo()会先构造一个临时Foo对象,再调用复制赋值运算符把临时对象的内容拷贝到*this中,确实会多产生一次临时对象的构造和析构开销,相比手动逐个赋值成员默认值,效率略低。
但这里需要权衡效率和可靠性:手动赋值虽然高效,但扩展性极差——一旦类新增成员,很容易忘记在clear中同步更新,导致类不变式被破坏。而*this = Foo()的写法能保证所有成员都被重置为默认状态,可靠性拉满。
如果想兼顾两者,C++11及以后可以用另一种方案:直接在当前对象的内存上重新构造默认对象:
#include <memory> // 引入std::destroy_at和std::construct_at void clear() { std::destroy_at(this); std::construct_at(this); }
这种方式跳过了赋值操作,直接销毁当前对象再重新构造默认实例,无论类是否可移动,效率都很高,同时也能保证所有成员被重置。不过要注意:如果类包含const成员或引用成员,这种方式就不适用了,因为无法在已有内存上重新构造这类成员。
内容的提问来源于stack exchange,提问作者andreee
相关产品推荐
相关产品推荐

