我可以总是依赖编译器的 RVO 吗?

问题描述

我有一个文件读入字符串变量的函数。而且我不确定什么是更好的实现方式:


            void readFile(const std::filesystem::path& path,std::string& dest)
            {
                std::ifstream input(path,std::ios::in | std::ios::binary);
                if (!input.is_open())
                {
                    // throw exception
                }
                const std::size_t size = std::filesystem::file_size(path);
                std::string().swap(dest);
                dest.resize(size);
                input.read(&dest[0],size);
                input.close();
                if (input.fail() && !input.eof())
                {
                    // throw exception
                }
            }

或者:

            std::string readFile(const std::filesystem::path& path)
            {
                std::ifstream input(path,std::ios::in | std::ios::binary);
                if (!input.is_open())
                {
                    // throw exception
                }
                const std::size_t size = std::filesystem::file_size(path);
                std::string buffer(size,'\0');
                input.read(&buffer[0],size);
                input.close();
                if (input.fail() && !input.eof())
                {
                    // throw exception
                }
                return buffer;
            }

要读取的文件大小可能是几个字节到几百兆字节,因此读取操作可能会非常昂贵。互联网上有很多建议总是更喜欢使用返回值的第二种方法,让编译器进行所需的优化。但是,如果效率对我很重要,我可以完全依赖编译器吗?我可以确定编译器总是更喜欢 RVO 而不是要返回的数据的冗余副本吗?

解决方法

正如其他人所提到的,不能保证编译器会对此进行优化,因为返回值是一个命名变量(请参阅 https://en.cppreference.com/w/cpp/language/copy_elision)。

但是,在我看来,如果启用优化,您几乎总是可以依赖 RVO,因为 RVO 是编译器可以执行的第一个也是最简单的优化之一。原因是,在底层架构中,没有办法直接返回一个大值(比CPU寄存器大)。这样做的方法是调用者函数将为返回值分配一个局部变量,并将指向 this 的指针传递给被调用者。如此有效,编译器已经在堆栈上分配了一个局部变量,并将使用这个变量而不是分配另一个相同的变量。编译器将直接在调用函数局部变量中就地构造您的字符串。

,

我有一个将文件读入字符串变量的函数。而且我不确定什么是更好的实现方式:

[...]

...但是如果效率对我来说很重要,我可以完全依赖编译器吗? ...

编写代码的第一条规则是让人类读者清楚。 “过早优化是万恶之源。”一旦你有了清晰的代码,就剖析,看看你的性能问题是否真的像你认为的那样;你可能会感到惊讶。

大多数开发者可能会发现

std::string readFile(const std::filesystem::path& path) { /* ... */ }

比使用“out”参数更清晰。 (如果文件读取性能真的那么重要,那么您可能想要的不是同步读取 std::ifstreamstd::string。)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...