Moon
Moon

Reputation: 111

C++ What's the difference between the way compiler accesses static members and accesses ordinary members?

Let's say that I designed a class like this :

// MyClass.h
#pragma once

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

then I can access each member like this :

// 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;
}

(From what I know, accessing class members by pointer only makes a slight difference: passing an address and dereferencing it.)

Here, what I'm curious about is the difference between this and the way the compiler accesses static members.

I already know that the memory for a static member is located somewhere outside the class instance, rather than inside it. (So every class instances use the same memory for their static members.)

Then, the only difference for accessing static one is "where to access"? Or there exists something beyond it?

Upvotes: 2

Views: 90

Answers (1)

Jerry Coffin
Jerry Coffin

Reputation: 490098

First of all, you should realize that a const static member of integer type often won't involve any memory access at all. Unless you use it in a way that (more or less) forces the compiler to do so (e.g., taking its address) this will often (usually?) become simply a symbolic name for a constant. So, given something like:

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

...you can normally expect that your i<bar comparison will turn out to be something like:

cmp rcx, 1234

...with no attempt at accessing any variable at all.

A non-const static member is basically a global variable with a kind of funny name. So, at link time the funny name (i.e., the combination of the name of the class and the name of the variable itself) will be mangled (or "decorated", in MS-speak) to produce a unique name for the variable, which will be allocated just like any other global variable. So, semi-representative code might look something like this:

mov rax, foo$$bar
cmp rcx, rax

A non-static variable is allocated on a per-object basis. When a member function is invoked, it receives this as a "hidden" parameter. Inside the function, it can access the variable by adding the appropriate offset, and dereferencing the result to get to the specified variable.

enter image description here

Computing the correct offset is pretty simple for single inheritance, but can get somewhat more complex in the case of something like virtual multiple inheritance.

Upvotes: 4

Related Questions