static data-member undefined external

Discussion in 'C++' started by Scott J. McCaughrin, Nov 9, 2004.

  1. The following program compiles fine but elicits this message from the
    linker: "undefined reference to VarArray::funct" and thus fails.

    It seems to behave as if the static data-member: VarArray::funct were
    an extern, but it is declared in the same file (q.v.). What is the
    remedy for this?

    =================



    #include <iostream.h>

    typedef void (*Funct)(int,int); // TYPE OF THE STATIC DATA-MEMBER


    class VarArray
    {
    static Funct funct; // HERE IS WHERE THE STATIC MEMBER IS DECLARED
    double* rows; // -> vector of doubles
    int order; // length of vector


    public:

    VarArray(int n) { order = n; rows = new double[order]; }
    ~VarArray() {}

    friend void SetVarArrayHandler(Funct); // WILL INIT STATIC MEMBER

    double& operator[](int index)
    {
    if (index > -1 && index < order) return rows[index];
    else (*funct)(index, order); // index < 0 or index > order-1
    }
    };


    void SetVarArrayHandler(Funct fp)
    { VarArray::funct = fp; } // INITS STATIC MEMBER TO: fp (= Quit)


    void Quit(int ndx, int len)
    {
    cerr << "index = " << ndx << " is out of bounds: [0 ... "
    << len-1 << "] -- quitting\n";
    exit(-1); // ABEND
    }



    int main()
    {
    SetVarArrayHandler(Quit); // WILL INIT STATIC MEMBER TO: Quit
    VarArray mat(3); // similar to: VarArray mat[3]

    cout << "mat[5] = " << mat[5] << endl; /* should invoke: Quit() */
    return 0;
    }
     
    Scott J. McCaughrin, Nov 9, 2004
    #1
    1. Advertising

  2. "Scott J. McCaughrin" <> wrote in message
    news:cmqqa1$vfi$...
    > The following program compiles fine but elicits this message from the
    > linker: "undefined reference to VarArray::funct" and thus fails.
    >
    > It seems to behave as if the static data-member: VarArray::funct were
    > an extern, but it is declared in the same file (q.v.). What is the
    > remedy for this?
    >


    Define VarArray::funct, didn't I explain this before?

    Add this code (not to a header file)

    Funct VarArray::funct; // HERE IS WHERE THE STATIC MEMBER IS DEFINED!!!!

    It's just like a global varaible, you can declare it in as many header files
    as you like but you must defined it somewhere (and once only).

    john
     
    John Harrison, Nov 9, 2004
    #2
    1. Advertising

  3. John Harrison <> wrote:

    : Add this code (not to a header file)

    : Funct VarArray::funct; // HERE IS WHERE THE STATIC MEMBER IS DEFINED!!!!

    : It's just like a global varaible, you can declare it in as many header files
    : as you like but you must defined it somewhere (and once only).

    : john

    John,

    Thank you for this info -- I will try it out.

    However, this is a _private_ data-member -- it is not only static but
    private as well.

    Are you sure this is appropriate, making a private member "just like a
    global"? It may be that access is still restricted, but what about the
    so-called "information hiding" that 'private' is supposed to ensure?


    -- Scott
     
    Scott J. McCaughrin, Nov 9, 2004
    #3
  4. Scott J. McCaughrin wrote:
    > John Harrison <> wrote:
    >
    > : Add this code (not to a header file)
    >
    > : Funct VarArray::funct; // HERE IS WHERE THE STATIC MEMBER IS DEFINED!!!!
    >
    > : It's just like a global varaible, you can declare it in as many header files
    > : as you like but you must defined it somewhere (and once only).
    >
    > : john
    >
    > John,
    >
    > Thank you for this info -- I will try it out.
    >
    > However, this is a _private_ data-member -- it is not only static but
    > private as well.
    >
    > Are you sure this is appropriate, making a private member "just like a
    > global"?


    It's not just "appropriate", it's required. Every static data member
    shall be defined at the namespace level if it's used in the program
    _outside_ the class definition or if it's of non-integral type (or both).

    > It may be that access is still restricted, but what about the
    > so-called "information hiding" that 'private' is supposed to ensure?


    Don't you give your header to the people who're going to use your class?
    What about "information hiding" in that case? Think about it.

    V
     
    Victor Bazarov, Nov 9, 2004
    #4
  5. John Harrison <> wrote:

    : "Scott J. McCaughrin" <> wrote in message
    : news:cmqqa1$vfi$...
    : > The following program compiles fine but elicits this message from the
    : > linker: "undefined reference to VarArray::funct" and thus fails.
    : >
    : > It seems to behave as if the static data-member: VarArray::funct were
    : > an extern, but it is declared in the same file (q.v.). What is the
    : > remedy for this?
    : >

    : Define VarArray::funct, didn't I explain this before?
    No.

    : Add this code (not to a header file)

    Why should I?

    : Funct VarArray::funct; // HERE IS WHERE THE STATIC MEMBER IS DEFINED!!!!

    No, it was declared as a statuc member within the class, making this
    extra declaration redundant.

    : It's just like a global varaible, you can declare it in as many header files
    : as you like but you must defined it somewhere (and once only).

    : john

    That is precisely the problem. To quote B.S. in Section 10.2.4 (Static
    Members) of "C++ Programming Language" (3rd Edition):

    "Maybe 'just one little global variable' isn't too unmanagemable, but
    that style leads to code that is useless except to its original
    programmer. It should be avoided."

    And I agree with B.S. Here is an example of why.

    Suppose someone just happens to declare an array as a global just before
    your "just liek a global" declaration, say:

    Funct test_array[5];
    : Funct VarArray::funct; // HERE IS WHERE THE STATIC MEMBER IS DEFINED!!!!


    Then they make this assignment: test_array[5] = (Funct)NULL;

    Need I say more? Is this not a classic example of why globals should be
    avoided?

    Now, this begs the question: how am I to declare/define a static member
    variable, if I cannot do it within the class? Follow the example of the
    vtbl, used to implement virtual functions. The vtbl for a class is a
    de facto static member, yet is not explicitly declared by the user. It
    is _not_ a global, so the side-effect problems plaguing globals don't
    affect it. Yet it still remains accessible to those object requiring it,
    via the vptr.

    My point here is simply that the static member was introduced in Section
    10.2.4 as an antidote for global variables, yet the necessity of declaring
    it "like a global" defeats that purpose.
     
    Scott J. McCaughrin, Nov 17, 2004
    #5
  6. Victor Bazarov <> wrote:
    : Scott J. McCaughrin wrote:
    : > John Harrison <> wrote:
    : >
    : > : Add this code (not to a header file)
    : >
    : > : Funct VarArray::funct; // HERE IS WHERE THE STATIC MEMBER IS DEFINED!!!!
    : >
    : > : It's just like a global varaible, you can declare it in as many header files
    : > : as you like but you must defined it somewhere (and once only).
    : >
    : > : john
    : >
    : > John,
    : >
    : > Thank you for this info -- I will try it out.
    : >
    : > However, this is a _private_ data-member -- it is not only static but
    : > private as well.
    : >
    : > Are you sure this is appropriate, making a private member "just like a
    : > global"?

    : It's not just "appropriate", it's required. Every static data member
    : shall be defined at the namespace level if it's used in the program
    : _outside_ the class definition or if it's of non-integral type (or both).

    No, it should _not_ be required: it is only necessary at present because
    the implementation (_not_ the language specification) requires it. That
    is, the implementations I have seen do not have the compiler defining the
    static member, so the user is expected to define it explicitly. Show me
    how the language's specification requires this -- it does not. A compiler
    could treat explicit static members the same way it does implicit statics,
    like the vtbl. The user is unable to define this, so the compiler defines
    it, then implements the vptr to access it. Thus, the "requirement" to
    explicitly define declared static members ensues from the implementations.

    : > It may be that access is still restricted, but what about the
    : > so-called "information hiding" that 'private' is supposed to ensure?

    : Don't you give your header to the people who're going to use your class?
    : What about "information hiding" in that case? Think about it.

    What does that have to do with it? Suppose the recipient of my headers is
    only concerned about the interface with publicly-declared functions, and
    may not even know enough about the language to be concerned about your
    requirement to explicitly define its static members?

    But "information hiding" here refers to security against unintended access
    to private members (static or otherwise). If I have to declare a static
    member at global level, here is what can happen:

    Funct array[5];
    Funct VarArray::funct; // a private static member of VarArray

    then: array[5] = (Funct)NULL; // unintended access to private member

    Think about that.
     
    Scott J. McCaughrin, Nov 18, 2004
    #6
  7. "Scott J. McCaughrin" <> wrote...
    > Victor Bazarov <> wrote:
    > : Scott J. McCaughrin wrote:
    > : > John Harrison <> wrote:
    > : >
    > : > : Add this code (not to a header file)
    > : >
    > : > : Funct VarArray::funct; // HERE IS WHERE THE STATIC MEMBER IS
    > DEFINED!!!!
    > : >
    > : > : It's just like a global varaible, you can declare it in as many
    > header files
    > : > : as you like but you must defined it somewhere (and once only).
    > : >
    > : > : john
    > : >
    > : > John,
    > : >
    > : > Thank you for this info -- I will try it out.
    > : >
    > : > However, this is a _private_ data-member -- it is not only static but
    > : > private as well.
    > : >
    > : > Are you sure this is appropriate, making a private member "just like a
    > : > global"?
    >
    > : It's not just "appropriate", it's required. Every static data member
    > : shall be defined at the namespace level if it's used in the program
    > : _outside_ the class definition or if it's of non-integral type (or
    > both).
    >
    > No, it should _not_ be required: it is only necessary at present because
    > the implementation (_not_ the language specification) requires it. That
    > is, the implementations I have seen do not have the compiler defining the
    > static member, so the user is expected to define it explicitly. Show me
    > how the language's specification requires this -- it does not.


    The only source of information I have about the language specification is
    the C++ language International Standard. In 9.4.2, paragraph 2, it says,
    "The definition for a static data member shall appear in a namespace scope
    enclosing the member's class definition." To me "shall" means "required".

    > A compiler
    > could treat explicit static members the same way it does implicit statics,
    > like the vtbl.


    What's "vtbl"? I can't find that word in the language Standard.

    > The user is unable to define this, so the compiler defines
    > it, then implements the vptr to access it.


    There is no reference to any of it in the language specification.

    > Thus, the "requirement" to
    > explicitly define declared static members ensues from the implementations.


    I somehow naively thought that it's the implementations that ensue from
    the requirements set forth by the language Standard document... I guess
    I was wrong then...

    >
    > : > It may be that access is still restricted, but what about the
    > : > so-called "information hiding" that 'private' is supposed to ensure?
    >
    > : Don't you give your header to the people who're going to use your class?
    > : What about "information hiding" in that case? Think about it.
    >
    > What does that have to do with it? Suppose the recipient of my headers is
    > only concerned about the interface with publicly-declared functions, and
    > may not even know enough about the language to be concerned about your
    > requirement to explicitly define its static members?


    I don't understand how what the recipient's "concerned about" relates to
    the fact that the compiler needs all the information necessary to properly
    create code that uses the objects of your class.

    > But "information hiding" here refers to security against unintended access
    > to private members (static or otherwise). If I have to declare a static
    > member at global level, here is what can happen:
    >
    > Funct array[5];
    > Funct VarArray::funct; // a private static member of VarArray
    >
    > then: array[5] = (Funct)NULL; // unintended access to private member


    What? Huh? What unintended access? This code has _undefined_ behaviour.
    There can be no "intent" here.

    > Think about that.


    Nothing to think about. Undefined behaviour is undefined behaviour.
    If you want to convince anybody that there can be something _definite_
    about the code you presented here, sorry, you're mistaken.

    V
     
    Victor Bazarov, Nov 18, 2004
    #7
  8. Victor Bazarov <> wrote:

    "Scott J. McCaughrin" <> wrote...
    : > Victor Bazarov <> wrote:
    : > : Scott J. McCaughrin wrote:
    : > : >

    (intermediate commentary elided for brevity)

    : > : > Are you sure this is appropriate, making a private member
    : > : > "just like a global"?
    >
    > : It's not just "appropriate", it's required. Every static data member
    > : shall be defined at the namespace level if it's used in the program
    > : _outside_ the class definition or if it's of non-integral type (or
    > : both).
    >

    (more intermediate responses frome me deleted for brevity)

    : The only source of information I have about the language specification is
    : the C++ language International Standard. In 9.4.2, paragraph 2, it says,
    : "The definition for a static data member shall appear in a namespace scope
    : enclosing the member's class definition." To me "shall" means "required".

    Victor:

    Thank you for citing the exact reference in the Standard, as it does shed
    light on my concern. Our exchange went:

    : > : > Are you sure this is appropriate, making a private member
    : > : > "just like a global"?
    >
    > : It's not just "appropriate", it's required.


    Yet, note omssion of the term "global" from your citation, which tells me
    that the Standard does not require static data members to reside in auto
    storage, thus permitting them to reside in static storage as I maintained.

    I suspect some of the confusion in this thread may arise from differing
    interpretations of that term: "required". You take it to mean whatever
    is stipulated by the Standard, while I read it to convey whatever a
    compiler was capable of implementing.

    : > But "information hiding" here refers to security against unintended
    : > access to private members (static or otherwise). If I have to declare
    : > a static member at global level, here is what can happen:
    : >
    : > Funct array[5];
    : > Funct VarArray::funct; // a private static member of VarArray
    : >
    : > then: array[5] = (Funct)NULL; // unintended access to private member

    : What? Huh? What unintended access? This code has _undefined_ behaviour.
    : There can be no "intent" here.

    Correct, which is why I said "unintended access". The behavior is indeed
    "undefined" since alignment and padding considerations (if any) make it
    so. But it is the _possibility_ of such access that worries me. Since
    `array[]' and `funct' are of the same type, it is indeed possible that
    the five elements array[0] ... array[4] can immediately precede `funct'
    in auto store, so that array[5] coincides with `funct' and thereby
    allow the spurious overwrite. Now, I readily concede that consigning
    the private static member `funct' to static store does not guarantee
    safety, but it can lessen the likelihood in cases where the static
    store is treated less casually than the stack is. That may be the
    best we can ever hope for.

    : > Think about that.

    : Nothing to think about. Undefined behaviour is undefined behaviour.
    : If you want to convince anybody that there can be something _definite_
    : about the code you presented here, sorry, you're mistaken.

    But I am not trying to do that: only to show the possibility. Where did
    I claim this would "definitely" happen, Victor? Indeed, if there is any
    misperception of definiteness at all, it may accrue from use of the term
    "private" to suggest that such data members are safe from unwarranted
    intrusion, when my example was only submitted to assail that contention.

    To put these matters into perspective, you may recall that my original
    post dealt with the compiler (GNU gpp) complaining about my static data
    member as an "undefined reference" (although I suspect it was the linker
    complaining). Well, that means that the symbol for my static data member
    could not be resolved to any kind of address, i.e., no storage had been
    set aside for it, despite my declaration of it in the class as a static.
    Thus, it was treating the symbol like an `extern' (I suspect other
    loaders might have even given me "undefined extern" as a more inform-
    ative diagnostic).

    I do not agree that the user should have to define storage for a class-
    level static member separate from its declaration, and so I submitted
    my suggestion that -- like any non-class static variable -- it be
    allocated in the static store implicity by the compiler when it first
    encounters the symbol. Thus the symbol does have a memory address to
    satisfy the linker.

    I only raised the "vtbl" issue by way of showing how the compiler can
    automatically define the static data member in static store without the
    necessity of an explicit definition from the user separate from his/her
    delcaration in its class. I am quite sure others can suggest far better
    examples to illustrate the feasibility of achieving such compiler def-
    inition. It should now only remain for the user to set values for the
    static member at their discretion.

    -- Scott
     
    Scott J. McCaughrin, Nov 19, 2004
    #8
  9. Scott J. McCaughrin wrote:
    > [...]
    > Yet, note omssion of the term "global" from your citation, which tells me
    > that the Standard does not require static data members to reside in auto
    > storage, thus permitting them to reside in static storage as I maintained.


    Not permitting. Requiring. Any object declared 'static' has static
    storage duration. "Global" usually means "declared/defined in the global
    namespace". Static data members are not necessarily defined in the global
    namespace. If the class is declared in a namespace other than global, so
    will any static data member of that class.

    > I suspect some of the confusion in this thread may arise from differing
    > interpretations of that term: "required". You take it to mean whatever
    > is stipulated by the Standard, while I read it to convey whatever a
    > compiler was capable of implementing.


    The capabilities of the compiler are chanelled by the requirements of the
    Standard. In this particular case, the Standard does NOT leave any room
    for the compiler to take any initiative WRT where to define the object.

    > : > But "information hiding" here refers to security against unintended
    > : > access to private members (static or otherwise). If I have to declare
    > : > a static member at global level, here is what can happen:
    > : >
    > : > Funct array[5];
    > : > Funct VarArray::funct; // a private static member of VarArray
    > : >
    > : > then: array[5] = (Funct)NULL; // unintended access to private member
    >
    > : What? Huh? What unintended access? This code has _undefined_ behaviour.
    > : There can be no "intent" here.
    >
    > Correct, which is why I said "unintended access". The behavior is indeed
    > "undefined" since alignment and padding considerations (if any) make it
    > so. But it is the _possibility_ of such access that worries me.


    There is always a possibility for undefined behaviour when such constructs
    are used. There is very little sense in blaming the language for that.

    > Since
    > `array[]' and `funct' are of the same type, it is indeed possible that
    > the five elements array[0] ... array[4] can immediately precede `funct'
    > in auto store,


    No, not in auto store. In static store.

    > so that array[5] coincides with `funct' and thereby
    > allow the spurious overwrite. Now, I readily concede that consigning
    > the private static member `funct' to static store does not guarantee
    > safety, but it can lessen the likelihood in cases where the static
    > store is treated less casually than the stack is. That may be the
    > best we can ever hope for.


    Still, if 'array[5]' is declared at the namespace level right there next
    to 'funct', the possibility of undefined behaviour still exists. It is
    not up to the language to prevent that.

    >
    > : > Think about that.
    >
    > : Nothing to think about. Undefined behaviour is undefined behaviour.
    > : If you want to convince anybody that there can be something _definite_
    > : about the code you presented here, sorry, you're mistaken.
    >
    > But I am not trying to do that: only to show the possibility.


    The possibility does _not_ rise from the fact that a member has to be put
    into static storage and defined at the namespace level.

    > Where did
    > I claim this would "definitely" happen, Victor? Indeed, if there is any
    > misperception of definiteness at all, it may accrue from use of the term
    > "private" to suggest that such data members are safe from unwarranted
    > intrusion, when my example was only submitted to assail that contention.


    "private", "protected" are NOT intended to prevent access to underlying
    memory by any potentially dangerous means, only by means of C++ code in
    a _valid_ C++ program. You give an example of an invalid program and base
    your derivations on the possibility that it might cause some unintended
    and unwanted effect. Speak about "what if"!

    >
    > To put these matters into perspective, you may recall that my original
    > post dealt with the compiler (GNU gpp) complaining about my static data
    > member as an "undefined reference" (although I suspect it was the linker
    > complaining). Well, that means that the symbol for my static data member
    > could not be resolved to any kind of address, i.e., no storage had been
    > set aside for it, despite my declaration of it in the class as a static.


    Not despite. Because of.

    > Thus, it was treating the symbol like an `extern' (I suspect other
    > loaders might have even given me "undefined extern" as a more inform-
    > ative diagnostic).


    Yes, essentially.

    > I do not agree that the user should have to define storage for a class-
    > level static member separate from its declaration, and so I submitted
    > my suggestion that -- like any non-class static variable -- it be
    > allocated in the static store implicity by the compiler when it first
    > encounters the symbol. Thus the symbol does have a memory address to
    > satisfy the linker.


    But that would be simply impossible. If you include your class definition
    with a static data member into more than one translation unit, and at the
    same time access that static data member in those translation units, where
    does the definition reside? If the compiler will create the definition as
    soon as it encounters the declaration, how many definitions is there going
    to be?

    > I only raised the "vtbl" issue by way of showing how the compiler can
    > automatically define the static data member in static store


    (a) Who said that 'vtbl' resides in static store?

    (b) There is no 'vtbl' in the standard, which suggests that making static
    data members behave similarly to 'vtbl' _may_ unnecessarily limit the
    implementations to doing something a certain way. A better example
    would be a template. Somehow implementations manage to resolve those
    things when they are created in every object module that uses them.

    > without the
    > necessity of an explicit definition from the user separate from his/her
    > delcaration in its class. I am quite sure others can suggest far better
    > examples to illustrate the feasibility of achieving such compiler def-
    > inition. It should now only remain for the user to set values for the
    > static member at their discretion.


    And where would they put those values? In the declaration? And what to
    prevent them to be different in different translation units?

    Yes, if you have a suggestion for fixing this unpleasant trouble with
    static data members rising from the fact that they have to be defined in
    the namespace separately from the class definition, please do make that
    suggestion to comp.std.c++, but you better (a) give proper examples of
    what problem you're trying to solve (preventing potential results of
    a program with undefined behaviour does not cut it) and (b) be prepared
    to answer questions like, "how is it going to work if ..".

    At this point, you _don't_ have a problem. You _invent_ one. The fact
    that the compiler (or the linker) requires you to define the static data
    member is merely _annoying_ (and only to you, I might add), and nothing
    to really make a fuss about. That's my point.

    V
     
    Victor Bazarov, Nov 19, 2004
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tim
    Replies:
    2
    Views:
    1,528
  2. Serge
    Replies:
    4
    Views:
    8,737
    Paavo Helde
    Dec 19, 2004
  3. Jason
    Replies:
    2
    Views:
    541
    Jonathan Mcdougall
    May 13, 2006
  4. dolphin
    Replies:
    3
    Views:
    1,381
    Pete Becker
    Dec 5, 2007
  5. Markus S
    Replies:
    3
    Views:
    1,048
    Markus S
    Jul 22, 2009
Loading...

Share This Page