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

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?

本文关键字:成员 函数 调用 开销 多少 临时对象 任何 变量 如果      更新时间:2023-10-16

i最近正在研究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等(。图书馆的文档指出,装载机类理想情况下应不包含任何成员变量。我想这是因为每次称为loadResource时,都会创建加载程序类的临时性来调用其loadResource成员函数。这就是我的问题所在:TResourceLoader{}.loadResource()的成本是多少?编译器是否能够删除临时性的创建,因为它不包含任何成员变量?有更好的方法吗?

应该没有显着的性能含义,尽管代码会受到稍微惩罚。为了更好地理解含义,让我们尝试将代码分解为类似于编译器生成的代码的事物:

来自:

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

to:

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();

在上面的代码中,编译器将看到构造函数和驱动器都是默认器,并且由于类的确没有成员,因此可以安全地省略这些成员。

您最终的结果是必须在自动存储中分配1个字节,在现代体系结构上通常意味着减少堆栈指针寄存器,然后通过增加。

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

是的,编译器将优化没有任何数据成员的临时变量的创建。基本上不需要代码。您可以自己验证它,并在Compiler Explorer等在线工具上使用各种优化级别。