static data-member undefined external | | |
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;
} | | | | re: static data-member undefined external
"Scott J. McCaughrin" <sjmccaug@bluestem.prairienet.org> wrote in message
news:cmqqa1$vfi$1@wildfire-pl.prairienet.org...[color=blue]
> 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?
>[/color]
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 | | | | re: static data-member undefined external
John Harrison <john_andronicus@hotmail.com> 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 | | | | re: static data-member undefined external
Scott J. McCaughrin wrote:[color=blue]
> John Harrison <john_andronicus@hotmail.com> 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"?[/color]
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).
[color=blue]
> It may be that access is still restricted, but what about the
> so-called "information hiding" that 'private' is supposed to ensure?[/color]
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 | | | | re: static data-member undefined external
John Harrison <john_andronicus@hotmail.com> wrote:
: "Scott J. McCaughrin" <sjmccaug@bluestem.prairienet.org> wrote in message
: news:cmqqa1$vfi$1@wildfire-pl.prairienet.org...
: > 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. | | | | re: static data-member undefined external
Victor Bazarov <v.Abazarov@comacast.net> wrote:
: Scott J. McCaughrin wrote:
: > John Harrison <john_andronicus@hotmail.com> 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. | | | | re: static data-member undefined external
"Scott J. McCaughrin" <sjmccaug@bluestem.prairienet.org> wrote...[color=blue]
> Victor Bazarov <v.Abazarov@comacast.net> wrote:
> : Scott J. McCaughrin wrote:
> : > John Harrison <john_andronicus@hotmail.com> 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.[/color]
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".
[color=blue]
> A compiler
> could treat explicit static members the same way it does implicit statics,
> like the vtbl.[/color]
What's "vtbl"? I can't find that word in the language Standard.
[color=blue]
> The user is unable to define this, so the compiler defines
> it, then implements the vptr to access it.[/color]
There is no reference to any of it in the language specification.
[color=blue]
> Thus, the "requirement" to
> explicitly define declared static members ensues from the implementations.[/color]
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...
[color=blue]
>
> : > 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?[/color]
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.
[color=blue]
> 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[/color]
What? Huh? What unintended access? This code has _undefined_ behaviour.
There can be no "intent" here.
[color=blue]
> Think about that.[/color]
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 | | | | re: static data-member undefined external
Victor Bazarov <v.Abazarov@comacast.net> wrote:
"Scott J. McCaughrin" <sjmccaug@bluestem.prairienet.org> wrote...
: > Victor Bazarov <v.Abazarov@comacast.net> wrote:
: > : Scott J. McCaughrin wrote:
: > : >
(intermediate commentary elided for brevity)
: > : > Are you sure this is appropriate, making a private member
: > : > "just like a global"?[color=blue]
>
> : 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).
>[/color]
(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"?[color=blue]
>
> : It's not just "appropriate", it's required.[/color]
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 | | | | re: static data-member undefined external
Scott J. McCaughrin wrote:[color=blue]
> [...]
> 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.[/color]
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.
[color=blue]
> 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.[/color]
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.
[color=blue]
> : > 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.[/color]
There is always a possibility for undefined behaviour when such constructs
are used. There is very little sense in blaming the language for that.
[color=blue]
> 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,[/color]
No, not in auto store. In static store.
[color=blue]
> 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.[/color]
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.
[color=blue]
>
> : > 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.[/color]
The possibility does _not_ rise from the fact that a member has to be put
into static storage and defined at the namespace level.
[color=blue]
> 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.[/color]
"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"!
[color=blue]
>
> 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.[/color]
Not despite. Because of.
[color=blue]
> 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).[/color]
Yes, essentially.
[color=blue]
> 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.[/color]
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?
[color=blue]
> I only raised the "vtbl" issue by way of showing how the compiler can
> automatically define the static data member in static store[/color]
(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.
[color=blue]
> 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.[/color]
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 |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,510 network members.
|