Re: Undefined symbol error for static const char
};
int main(int argc, char **argv) {
std::vector<char> vect;
vect.resize(10, cls::foo);
return 0;
}
$ g++ sc.cpp
Undefined symbols:
"cls::foo", referenced from:
__ZN3cls3fooE$non_lazy_ptr in ccB49b7c.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
And the linker is right: it's not defined. Roughly speaking,
if your code takes its address (and that includes passing it
by reference) you have to define it.
const char cls::foo; // definition
The declaration in the class definition is a declaration, not
a definition.
To which I might add (considering that others have mentionned
that it does compile and link successfully with certain versions
of g++): not providing the definition is undefined behavior; the
compiler doesn't have to reject the code. In fact, your results
are likely to vary depending on whether vector::resize is inline
or not, and the level of optimization.
I wondered about that. There is no mention in the standard of
UB in case of missing declaration. I assumed the code would be
incorrect and the error caught at link time.
What about =A72.2 (paragraphs 2 and 3):
An exprssion is potentially evaluated unless[...] . An
object or non-overloaded function is used if its name
appears in a potentially-evaluated expression. [...]
Every program shall contain exactly one definition of
every non-inline function or object that is used in that
program; no diagnostic required.
That "no diagnostic required" is the signal that the behavior is
undefined.
I understand that depending on the level of optimisation, a
reference on the actual data might or might not be needed but
could it really happen that a compiler generates code but some
memory location is missing and causing UB ?
In practice, I think there will be only two possible behaviors:
the code links and works, or it fails to link with an error
message. The standard has (or had---I think C++0x may introduce
this concept in some places) a concept of "alternate behaviors"
or "limited undefined behavior". All programs basically fall
into four categories: requiring a diagnostic (what happens after
the diagnostic is undefined), undefined behavior (diagnostic not
required, but allowed; anything else goes as well), unspecified
behavior (program must compile and run, but what happens when it
runs is unspecified), implementation defined behavior (must be
documented by the implementation) and fully defined behavior
(although in practice no program totally avoids implementation
defined behavior---main returns an int, and the size and
reprentation of an int are implementation defined). There are a
lot of cases where in practice, the code will either fail to
compiler, or it will compile and work as expected, but the only
category above in which such code fits is undefined behavior, so
that's what the standard calls it. (E.g. including <iostream>
and <vector>, then using an std::ostream_iterator is undefined
behavior. In practice, however, if <iostream> or <vector>
include all of <iterator>, it will work as expected; if they
don't, it will fail to compile. And I can't conceive of any
other possible behavior in practice.)
--
James Kanze