简体   繁体   中英

Static variable shadowing global

I am trying to create an object using placement new (I know to use smart pointers, this is just to learn). My code is as follows:

#include <vector>
#include <iostream>
#include <memory>


using namespace std; // please excuse this

// if you change like 19 to arr1 (or any other var name) instead of arr and line 40 to arr1 then it works

struct A
{
    int in = 999;
    A()
    {cout << "A ctor\n";}
    ~A()
    {cout << "A dtor\n";}
};

char arr[sizeof(A)];

class B
{
    public:
    static char arr[sizeof(A)];

    const static A* a_obj;

    B()
    {
        cout << "B ctor\n";
        //cout << (a_obj->in) << endl;
    }
    ~B()
    {
        cout << "B dtor\n";
    }
};



const A* B::a_obj = new(arr) A;


int main()
{
    B g;
}

I have created a global array named arr and another array named arr in B . It seems like when I do my placement new the arr being used is from the class as I get what I think are linker errors.

Why is this happening? why isn't the global arr being used? If i change the placement new to use my renamed global array it works. I think it has to do something with lookups but I don't have a concrete answer.

From the C++ 2017 Standard (12.2.3.2 Static data members)

2 The declaration of a non-inline static data member in its class definition is not a definition and may be of an incomplete type other than cv void. The definition for a static data member that is not defined inline in the class definition shall appear in a namespace scope enclosing the member's class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator. The initializer expression in the definition of a static data member is in the scope of its class (6.3.7).

So in this definition of the static data member

const A* B::a_obj = new(arr) A;

the unqualified name arr is at first searched in the scope of the class B . And the class B indeed declares such a name

static char arr[sizeof(A)];

If you want to use the name from the global namespace then use the qualified name

const A* B::a_obj = new(::arr) A;

Here is a demonstrative program

#include <iostream>

struct A
{
    const static int N = 10;
    static int n1;
    static int n2;
};

const int N = 20;

int A::n1 = N;
int A::n2 = ::N;


int main() 
{
    std::cout << "A::n1 = " << A::n1 << std::endl;
    std::cout << "A::n2 = " << A::n2 << std::endl;

    return 0;
}

Its output is

A::n1 = 10
A::n2 = 20

The reason arr is attribute to the class B and not the global scope is due to unqualified name lookup rules.

Specifically:

Static data member definition For a name used in the definition of a static data member, lookup proceeds the same way as for a name used in the definition of a member function.

Meaning:

struct X {
    static int x;
    static const int n = 1; // found 1st
};
int n = 2; // found 2nd.
int X::x = n; // finds X::n, sets X::x to 1, not 2

If you are intrested you can see more information here: http://en.cppreference.com/w/cpp/language/unqualified_lookup

As people suggested to get what you want just use:

const A* B::a_obj = new(::arr) A;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM