如果 class 没有任何成员变量,通过临时对象调用 class 的成员函数的成本是多少?

What is the cost of calling a member function of a class through a temporary object if the class doesn't have any member variables?

我最近在研究 ENTT 库的源代码,我遇到了类似于以下代码片段的东西(请注意,我已经大大简化了事情以使我的问题简短):

// Note that this class doesn't contain any member variables
class TextureLoader
{
public:

   TextureLoader() = default;
   ~TextureLoader() = default;

   std::shared_ptr<Texture> loadResource(const std::string& textureFilePath) const;
};

template<typename TResource, typename TResourceLoader, typename... Args>
std::shared_ptr<TResource> loadResource(Args&&... args)
{
   // Note how a temporary TResourceLoader is created to invoke its loadResource member function
   return TResourceLoader{}.loadResource(std::forward<Args>(args)...));
}

int main()
{
   std::string texFilePath = "tex.png";
   std::shared_ptr<Texture> myTexture = loadResource<Texture, TextureLoader>(texFilePath);
   return 0;
}

如您所见,loadResource函数模板能够加载任何资源类型(例如TextureShaderModelSound , ETC。)。该库的文档指出加载程序 class 理想情况下不应包含任何成员变量。我想这是因为每次调用 loadResource 时,都会创建传递给它的加载程序 class 的临时文件来调用它的 loadResource 成员函数。这就是我的问题所在:TResourceLoader{}.loadResource() 的成本是多少?编译器是否能够删除临时的创建,因为它不包含任何成员变量?有更好的方法吗?

是的,编译器将优化没有任何数据成员的临时变量的创建。基本上不需要代码生成器。您可以自己验证并在 Compiler Explorer.

等在线工具上尝试各种优化级别

虽然代码会受到轻微的惩罚,但应该不会对性能产生重大影响。为了更好地理解其含义,让我们尝试将代码分解为类似于编译器生成的代码的内容:

发件人:

return TResourceLoader{}.loadResource(std::forward<Args>(args)...));

收件人:

char Storage[1]; // Any object in C++ is at least 1 byte, including classes with no members
Storage(&Storage); // Pseudo-code illustrating calling constructor
loadResource(&Storage, <args>); // considering loadResource can't be inlined
Storage.~Storage();

在上面的代码中,编译器会发现构造函数和析构函数都是默认的,并且由于 class 没有成员,因此实际上是微不足道的 - 所以可以安全地省略它们。

您最终需要在自动存储中分配 1 个字节,这在现代体系结构中通常意味着递减堆栈指针寄存器,然后递增它。

这是非常快的操作,但仍然不是瞬时的。