C++构造函数初始化列表中std::array的NRVO优化问题咨询
问题解答
1. 无拷贝现象是否为NRVO优化的作用
是的,你观察到的无拷贝结果确实是**NRVO(具名返回值优化)**生效的结果。std::array是固定大小的聚合类型,所有数据直接存储在栈内存中,没有堆上分配的资源,它的移动操作和拷贝操作开销完全等价。你的测试场景中编译器会直接将get_arr函数内创建的局部数组对象,直接构造到S类成员arr_的内存地址上,完全省略了拷贝/移动的步骤。
2. 依赖RVO初始化不可移动聚合成员的写法是否合规、是否推荐
这种写法完全符合C++标准规范,且在你的场景下是非常推荐的:
- 首先
std::array的选型没有问题:对于固定大小的缓冲区场景,std::array没有动态内存分配开销,比std::vector性能高得多,是最优选择。 - 其次NRVO的可靠性足够高:虽然C++标准没有强制要求编译器实现RVO/NRVO,但目前所有主流编译器(GCC、Clang、MSVC)哪怕在
-Og甚至-O0优化等级下,都会对单返回路径的具名返回值做NRVO优化,你的get_arr只有单一返回对象,不存在NRVO失效的风险。 - 哪怕极端情况NRVO真的失效,最多也只会产生一次20字节的
std::array拷贝,开销几乎可以忽略,完全不会成为性能瓶颈。
3. 是否推荐将get_arr逻辑迁移到构造函数体内实现
完全不推荐。如果将逻辑迁移到构造函数体内,你需要先默认初始化arr_,再对其做赋值操作,反而多了一次初始化和赋值的开销,性能比初始化列表依赖NRVO的写法差得多。
测试代码
#include <algorithm> #include <array> #include <numeric> #include <string> std::array<std::byte, 20> get_arr(const std::string& s) { std::array<std::byte, 20> a; // 真实业务逻辑的简易模拟算法 std::transform(s.begin(), s.end(), a.begin(), [](auto b) { return std::byte(unsigned(b) << 1U); }); return a; } struct S { explicit S(const std::string& s) : arr_(get_arr(s)) {} std::array<std::byte, 20> arr_; }; int main(int /*argc*/, char* argv[]) { // 真实场景下会从文件读取约6亿条字符串 S s(argv[1]); return static_cast<int>(s.arr_[19]); // 引用成员避免被优化消除 }
内容的提问来源于stack exchange,提问作者Oliver Schönrock
相关产品推荐
相关产品推荐

