【问题标题】:C++ What's the difference between the way compiler accesses static members and accesses ordinary members?C++编译器访问静态成员和访问普通成员的方式有什么区别?
【发布时间】:2020-09-06 05:19:24
【问题描述】:

假设我设计了一个这样的类:

// MyClass.h
#pragma once

class MyClass
{
public:
    const int member = 1; // Since it is a const-integral type var...
    static const int s_member;
    ...
};

然后我可以像这样访问每个成员:

// MyClass.cpp
const int MyClass::s_member = 2; // Initialization of a static member
int main()
{
    MyClass* myClass = new MyClass;
    std::cout << "access to an ordinary member : " << myClass->member << " OR " << (*myClass).member << std::endl;
    std::cout << "access to a static member : " << MyClass::s_member << std::endl;
    
    ...

    return 0;
}

(据我所知,通过指针访问类成员只会产生细微的差别:传递地址并取消引用它。)

在这里,我很好奇的是这与编译器访问静态成员的方式之间的区别。

我已经知道静态成员的内存位于类实例之外的某个地方,而不是在它内部。 (所以每个类实例都为其静态成员使用相同的内存。)

那么,访问静态的唯一区别是“从哪里访问”?还是存在着超越它的东西?

【问题讨论】:

  • 如果我正确理解了您的问题,那么不,访问静态成员和非静态成员除了它们所在的位置之外没有区别。
  • 静态成员变量、静态局部变量、静态全局变量和非静态全局变量——它们都具有被分配一次的共同性质(而不是每次调用函数或实例化对象时) ),因此在整个程序执行过程中具有相同的内存地址。
  • '编译器',或者说你的程序在运行时,通过它们的固定地址'访问'静态成员,通过它们与this的当前值的偏移来'访问'非静态成员。
  • @Ahmn21 不,它没有。这个问题根本没有解决非静态非常量成员。

标签: c++


【解决方案1】:

首先,您应该意识到整数类型的const static 成员通常根本不会涉及任何内存访问。除非您以(或多或少)强制编译器这样做(例如,获取其地址)的方式使用它,否则这通常会(通常?)成为常量的简单符号名称。所以,给定类似的东西:

class foo {
    static const int bar = 1234;
public:
    void baz() { 
        for (int i=0; i<bar; i++)
            // ...
   }
};

...您通常可以预期您的 i&lt;bar 比较结果类似于:

cmp rcx, 1234

...根本没有尝试访问任何变量。

一个非常量的static 成员基本上是一个具有某种有趣名称的全局变量。因此,在链接时,有趣的名称(即类的名称和变量本身的名称的组合)将被破坏(或“修饰”,用 MS 的话)以产生一个唯一的变量名称,它将像任何其他全局变量一样被分配。因此,半代表性代码可能看起来像这样:

mov rax, foo$$bar
cmp rcx, rax

一个非静态变量是基于每个对象分配的。调用成员函数时,它会接收this 作为“隐藏”参数。在函数内部,它可以通过添加适当的偏移量来访问变量,并取消引用结果以获取指定的变量。

计算正确的偏移量对于单继承来说非常简单,但在虚拟多继承的情况下可能会变得更加复杂。

【讨论】:

  • 谢谢,您的回答有助于我了解它!弹出问题:在最后一行中,您提到了多重继承类的“稍微复杂一些”。这是否意味着我必须为此付出额外的性能成本?
  • @Moon:是的,通常会有性能成本(尽管它很小)。基本上,只是一个额外的加法(从整个对象的地址开始,进行一次加法以到达特定基类子对象的开头,然后再进行一次加法以到达该对象内的偏移量)。
  • @Moon • 如果多继承的性能成本是一个问题,请配置profile profile。通常手卷替代品的性能较差。静态多态性 (q.v. CRTP) 可以提高性能,但代价是可维护性较差,需要大量样板代码和处理大量模板代码。
  • @Eljay “个人资料”是什么意思?由于我不在一个说英语的国家,我无法推断这个词在这种情况下的含义,其中很多都有。
  • @Moon • 分析软件意味着衡量其优化构建的性能。如果不进行分析,则试图进行性能改进只是盲目的猜测,没有实际理由的基础。编译器优化器非常好。分析软件还可以告诉您性能瓶颈所在,这样您就不会浪费精力对不重要的东西进行微优化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多