C++自构造最佳实践:拷贝/移动构造函数如何处理自身调用?
C++自拷贝/移动构造的最佳实践
首先明确:你给出的示例代码虽然能通过编译,但属于触发未定义行为的写法——因为在拷贝构造函数被调用时,源对象(比如f、g、h)还处于构造过程中,成员变量的状态完全不确定,访问foo.val这种操作的结果是不可预测的。
针对拷贝/移动构造函数被对象自身调用的场景,最佳实践如下:
从源头杜绝这类代码逻辑:正常业务逻辑里,完全没有理由用一个正在构造的对象去初始化它自己。比如
Foo f(f);这种写法本身就是错误的逻辑漏洞,应该直接修正,而非让构造函数去兼容这种不合理场景。不要在拷贝构造函数中做自检查:和拷贝赋值运算符需要检查自赋值不同,拷贝构造是初始化新对象的过程。当发生自拷贝构造时,源对象还未完成构造,
this == &other的检查不仅没有意义(对象未完全创建,this的有效性都无法保证),而且这种场景本身就不是合法使用场景,没必要兼容。重视编译器警告:主流编译器(GCC、Clang、MSVC)都会对这类自初始化代码发出警告,提示你正在使用未初始化的对象。看到这类警告一定要立即修正代码,而非忽略或强行“修复”构造函数。
移动构造的自调用更要避免:如果是移动构造函数被自身调用,情况会更严重——移动操作需要转移源对象的资源,但此时源对象的资源根本没初始化,执行移动操作只会导致更严重的未定义行为(比如空指针解引用、资源泄露等),绝对不能出现这种写法。
再回到你的示例代码:三个初始化语句都会触发自拷贝构造,此时foo.val是未初始化的栈内存值,输出结果随机,程序行为完全不可控,必须删掉这类写法。
内容的提问来源于stack exchange,提问作者shuhalo
相关产品推荐
相关产品推荐

