C++20下如何避免Split方法返回CList时触发两次昂贵拷贝构造?
问题背景
现有代码实现了字符串分割功能:
CList<CString> Split(char delim) { CList<CString> subStrings; for (char* ps = Buffer(); *ps; ps++) { char* pe; for (pe = ps; *pe && (*pe != delim); pe++) ; subStrings.Append(CString(ps, int(pe - ps))); if (!*pe) break; ps = pe; } return subStrings; } // 调用代码 CList<CString> values = s.Split(';');
上述代码执行调用逻辑时会触发两次CList拷贝构造:
- Split方法内栈上局部变量
subStrings离开作用域时,被拷贝到编译器维护的临时存储区 - 临时对象再拷贝到
values变量
编译环境已支持C++20标准,要求不做根本性代码改动(如新增输出参数)的前提下,消除这两次拷贝开销。
解决方案
方案1:为
CList类实现移动构造函数和移动赋值运算符
只要给CList补充符合C++标准的移动语义实现,无需修改现有业务代码,编译器就会优先用移动构造代替拷贝构造。移动操作仅会转移列表内部的资源指针,不会复制元素,开销极低。如果使用的是MFC原生不支持移动的CList,可以简单继承封装一个支持移动的子类,原有Split方法的返回值声明、调用代码都无需调整。方案2:开启编译器返回值优化(RVO)
C++17及以上标准已将*具名返回值优化(NRVO)*列为标准支持的优化项,主流编译器(MSVC、GCC、Clang)在O2及以上优化等级下,会直接将Split内部的subStrings对象构造在外部values的内存地址上,完全消除两次拷贝操作,不需要修改任何代码。
内容的提问来源于stack exchange,提问作者Razzupaltuff
相关产品推荐
相关产品推荐

