Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

hidden static

73 views
Skip to first unread message

Popping mad

unread,
Nov 18, 2016, 8:49:24 PM11/18/16
to
I've a declared static as a public member of an
object but it doesn't seem to show up in the compiler

/home/ruben/src/test_static/test.cpp|22| undefined reference to `blah::A::here'


If I put it on top it errors are a private member. When I move it
to public, it is not being seen

The three test case files look like this


test.cpp

18 #include "test.h"
19 #include <iostream>
20 namespace blah{
21 void A::read(int in){
22 A::here = in;
23 std::cout << here << std::endl;
24 }
25 }


test.h

1 namespace blah{
2 class A{
3 public:
4 static int here;
5 A(int in=0){
6 here = in;
7 };
8 void read(int);
9 };
10
11 }
~

main.cpp
18 #include "test.h"
19 #include <iostream>
20 namespace std{
21
22 int main(int argc, char** argv){
23
24 blah::A* a = new blah::A{9};
25 cout << a->here << endl;
26 return 0;
27 }
28
29 }
~
makefile

1 CXX:=g++
2 CXXFLAGS:=-Wall -ggdb -pg -pthread
3
4 LDFLAGS:=-L/usr/local/lib/mysql -lmysqlpp -lmysqlclient
5
6 test : test.o main.o
7 ${CXX} ${CXXFLAGS} -o testme test.o main.o
8
9 main.o : main.cpp
10 ${CXX} ${CXXFLAGS} -o main.o -c main.cpp
11
12 test.o : test.cpp test.h
13 ${CXX} ${CXXFLAGS} -c test.cpp
14
15 clean :
16 rm testme *.o make.deps
17 touch *.cpp *.h
18
19 include make.deps
20 make.deps: *.cpp ; gcc -M *.cpp >$@
~

I need an extern?
1 || g++ -Wall -ggdb -pg -pthread -o testme test.o main.o
2 || /usr/lib/gcc/x86_64-pc-linux-gnu/6.2.1/../../../../lib/gcrt1.o: In function `_start':
3 || (.text+0x20): undefined reference to `main'
4 || test.o: In function `blah::A::read(int)':
5 /home/ruben/src/test_static/test.cpp|22| undefined reference to `blah::A::here'
6 /home/ruben/src/test_static/test.cpp|23| undefined reference to `blah::A::here'
7 || main.o: In function `std::main(int, char**)':
8 /home/ruben/src/test_static/main.cpp|25| undefined reference to `blah::A::here'
9 || main.o: In function `blah::A::A(int)':
10 /home/ruben/src/test_static/test.h|6| undefined reference to `blah::A::here'

Ian Collins

unread,
Nov 18, 2016, 10:07:14 PM11/18/16
to
Who have declared A::here, but you haven't defined it anywhere.

--
Ian

Paavo Helde

unread,
Nov 19, 2016, 3:30:27 AM11/19/16
to
On 19.11.2016 3:49, Popping mad wrote:
> I've a declared static as a public member of an
> object but it doesn't seem to show up in the compiler
>
> /home/ruben/src/test_static/test.cpp|22| undefined reference to `blah::A::here'

See https://isocpp.org/wiki/faq/ctors#link-errs-static-data-mems

While there, consider reading the whole https://isocpp.org/faq



Popping mad

unread,
Nov 19, 2016, 12:01:22 PM11/19/16
to
On Sat, 19 Nov 2016 10:30:14 +0200, Paavo Helde wrote:

> See https://isocpp.org/wiki/faq/ctors#link-errs-static-data-mems
>
> While there, consider reading the whole https://isocpp.org/faq


This is an excellent explanation, but I'm still not clear on this. I
think it is saying that a static has to be declared and defined within a
compilational unit. I'm not sure why, though. And I've asked before,
and read, but I'm still not clear on what a compilation unit is.

Paavo Helde

unread,
Nov 19, 2016, 5:12:42 PM11/19/16
to
On 19.11.2016 19:01, Popping mad wrote:
> On Sat, 19 Nov 2016 10:30:14 +0200, Paavo Helde wrote:
>
>> See https://isocpp.org/wiki/faq/ctors#link-errs-static-data-mems
>>
>> While there, consider reading the whole https://isocpp.org/faq
>
>
> This is an excellent explanation, but I'm still not clear on this. I
> think it is saying that a static has to be declared and defined within a
> compilational unit. I'm not sure why, though.

There are other things in C++ which are declared in a header file and
then defined in some translation unit. The prime example are functions
(member and non-member). That's just the way how C++ does things.

When defining a class static member in some cpp file, one tells the
compiler to reserve memory for it in an the data segment of this
translation unit, plus one also specifies the arguments instructing the
compiler how to construct it.

However, for some simpler scenarios the initialization of the class
static member can be written directly in the declaration, which is
probably the most confusing point here.

> And I've asked before,
> and read, but I'm still not clear on what a compilation unit is.

It is just whatever is compiled into a single object .o/.obj file.

hth
Paavo

Juha Nieminen

unread,
Nov 21, 2016, 2:52:47 AM11/21/16
to
Popping mad <rai...@colition.gov> wrote:
> This is an excellent explanation, but I'm still not clear on this. I
> think it is saying that a static has to be declared and defined within a
> compilational unit. I'm not sure why, though. And I've asked before,
> and read, but I'm still not clear on what a compilation unit is.

A static member variable needs to exist somewhere in the executable
(because, among other things, you need to be able to eg. have a pointer
pointing to it). You have to tell the compiler which compilation unit
(in practice which object file) the actual instance of that variable is.
The compiler won't guess; you need to tell it explicitly where it should
be put.

(Incidentally, C++17 will introduce the concept of inline variables,
which will allow you to define static member variables in the header
file itself, causing the linker to merge all the instantiations into
one. But that will be available only after compilers start supporting
it.)

Scott Lurndal

unread,
Nov 21, 2016, 8:26:16 AM11/21/16
to
Juha Nieminen <nos...@thanks.invalid> writes:
>Popping mad <rai...@colition.gov> wrote:
>> This is an excellent explanation, but I'm still not clear on this. I
>> think it is saying that a static has to be declared and defined within a
>> compilational unit. I'm not sure why, though. And I've asked before,
>> and read, but I'm still not clear on what a compilation unit is.
>
>A static member variable needs to exist somewhere in the executable
>(because, among other things, you need to be able to eg. have a pointer
>pointing to it).

The confusing part for some folks is that gcc/binutils, when using -O3, won't
require the definition unless the address of the static const value
is taken. Remove -O3 and you'll start getting link errors.

Chris Vine

unread,
Nov 21, 2016, 9:48:39 AM11/21/16
to
My recollection in the case of the declaration of a const static
integer member variable (typically with a literal value) is that you
don't need to provide a definition for it if it is not ODR-used,
whatever the optimization level. Taking an address is one way of
ODR-using it. Casting it to lvalue of another type is another. I don't
at the moment have the C++ standard in front of me to give you the
reference.

These days I guess you would probably declare such a static member
variable constexpr rather than const anyway.

Chris Vine

unread,
Nov 21, 2016, 12:31:24 PM11/21/16
to
I do now. It's §9.4.2/3. "If a non-volatile const static data member
is of integral or enumeration type, its declaration in the class
definition can specify a brace-or-equal-initializer in which every
initializer-clause that is an assignment-expression is a constant
expression (5.20). ... . The member shall still be defined in
a namespace scope if it is odr-used (3.2) in the program and the
namespace scope definition shall not contain an initializer." This
implies that the initialised const static integral member need not be
defined in namespace scope (its declaration is sufficient) if it is not
ODR-used.

Chris

Chris Vine

unread,
Nov 21, 2016, 1:18:29 PM11/21/16
to
On Mon, 21 Nov 2016 17:31:03 +0000
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> On Mon, 21 Nov 2016 14:48:15 +0000
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > On Mon, 21 Nov 2016 13:26:07 GMT
> > sc...@slp53.sl.home (Scott Lurndal) wrote:
[snip]
> > > The confusing part for some folks is that gcc/binutils, when using
> > > -O3, won't require the definition unless the address of the static
> > > const value is taken. Remove -O3 and you'll start getting link
> > > errors.
> >
> > My recollection in the case of the declaration of a const static
> > integer member variable (typically with a literal value) is that you
> > don't need to provide a definition for it if it is not ODR-used,
> > whatever the optimization level. Taking an address is one way of
> > ODR-using it. Casting it to lvalue of another type is another. I
> > don't at the moment have the C++ standard in front of me to give you
> > the reference.
>
> I do now. It's §9.4.2/3. "If a non-volatile const static data member
> is of integral or enumeration type, its declaration in the class
> definition can specify a brace-or-equal-initializer in which every
> initializer-clause that is an assignment-expression is a constant
> expression (5.20). ... . The member shall still be defined in
> a namespace scope if it is odr-used (3.2) in the program and the
> namespace scope definition shall not contain an initializer." This
> implies that the initialised const static integral member need not be
> defined in namespace scope (its declaration is sufficient) if it is
> not ODR-used.

However I do now recall having experiences similar to the one you
mention. Some forms of ODR-use, such as assigning to a const
reference, may be optimized out with a sufficiently high level of
optimization, and will compile and link even though technically the
code in question is not conformant. That may be what you had in mind.
But where the static member is not ODR-used, you should be safe from
that problem.

Juha Nieminen

unread,
Nov 22, 2016, 4:36:15 AM11/22/16
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> However I do now recall having experiences similar to the one you
> mention. Some forms of ODR-use, such as assigning to a const
> reference, may be optimized out with a sufficiently high level of
> optimization, and will compile and link even though technically the
> code in question is not conformant. That may be what you had in mind.
> But where the static member is not ODR-used, you should be safe from
> that problem.

Is this similar to what may happen if you make an extern function/method
implementation inline? The optimizer may optimize it away, causing a
linker error if it's being called from somewhere else than the
compilation unit where it's implemented. (Or at least I remember some
version of gcc doing that.)

Chris Vine

unread,
Nov 22, 2016, 6:12:14 PM11/22/16
to
I'm not really sure about that one. In C, inline functions have
internal linkage by default, which seems logical. In C++ they have
external linkage by default, which on the face of it seems illogical
but I am sure there is a reason for it. If you declare a C++ inline
function extern I should have thought it would have no effect at all,
since functions don't have storage - they just have linkage/visibility.
So the extern declaration seems redundant.

Chris

Juha Nieminen

unread,
Nov 23, 2016, 2:07:15 AM11/23/16
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> I'm not really sure about that one. In C, inline functions have
> internal linkage by default, which seems logical. In C++ they have
> external linkage by default, which on the face of it seems illogical
> but I am sure there is a reason for it. If you declare a C++ inline
> function extern I should have thought it would have no effect at all,
> since functions don't have storage - they just have linkage/visibility.
> So the extern declaration seems redundant.

What I meant was that in one compilation unit you have like:

void foo();
int main() { foo(); }

and then in another compilation unit you have:

inline void foo() { std::cout << "hello"; }

At least in the past, with some version of gcc, this may have produced
a linker error.

ruben safir

unread,
Nov 23, 2016, 5:52:06 AM11/23/16
to
On 11/22/2016 06:12 PM, Chris Vine wrote:
> I'm not really sure about that one. In C, inline functions have
> internal linkage by default, which seems logical. In C++ they have
> external linkage by default, which on the face of it seems illogical


why?

Chris Vine

unread,
Nov 23, 2016, 6:30:50 AM11/23/16
to
Ah right, I see what you mean. With breaches of the One Definition Rule
of this kind, the result you mention seems highly plausible, perhaps
even likely.

Chris

Chris Vine

unread,
Nov 23, 2016, 6:38:35 AM11/23/16
to
Every ODR-user of an inline function has to see the definition. So what
then is the point of giving it external linkage in C++? (I don't know
the answer to that question, it is not rhetorical.)

Öö Tiib

unread,
Nov 23, 2016, 7:50:50 AM11/23/16
to
May be it is for to make sure that the function-local static variables
in inline function are same for all instances. C++ compilers aggressively
ignore that suggestion given by 'inline' keyword to inline the function.
Therefore the 'inline' keyword basically means "function with external
linkage whose body may be is defined in header that may be is
included in several compilation units without causing ODR violations".

Tim Rentsch

unread,
Nov 23, 2016, 12:36:45 PM11/23/16
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:

> In C, inline functions have internal linkage by default, [...].

I believe this is not exactly right. As I read the C standard, a
function definition that has 'inline' but does not have 'extern'
still has external linkage, but does not provide an external
definition. Any call to said function might call the inline one
or it might call the externally defined one. (Who thought _that_
rule up? Sounds like a recipe for disaster.) So inline in C is
sort of like internal linkage, and sort of not.

> In C++ they have external linkage by default, [...].

AFAICT C++ is the same as C as far as linkage is concerned (ie,
for inline functions), but is more strict about how inline
functions may be defined in other translation units. Also, C++
allows more latitude for use of 'static' variable definitions
in inline functions.

Disclaimer: all of the foregoing is right to the best of my
understanding, but especially in the case of C++ there may be
something I missed or overlooked.
0 new messages