Topic: ODR violation


Author: tpochep <tpochep@mail.ru>
Date: Tue, 29 May 2007 11:05:26 CST
Raw View
Hello.

I have some very naive questions.

3.2 of ISO/IEC 14882 specifies the one definition rule. Item 5
describes which entities can have more than one definition in
different translation units. And:

[citation]
- each definition of D shall consist of the same sequence of tokens;
and
- in each definition of D, corresponding names, looked up according to
3.4, shall refer to an entity defined within the definition of D, or
shall refer to the same entity, after overload resolution (13.3) and
after matching of partial template specialization (14.8.3), except
that a name can refer to a const object with internal or no linkage if
the object has the same integral or enumeration type in all
definitions of D, and the object is initialized with a constant
expression (5.19), and the value (but not the address) of the object
is used, and the object has the same value in all definitions of D;
and .... (parts about overloaded operators, default argumenst and
implicitly-defined constructors are skipped)
[/citation]

So, first of all, if I understand correctly, the following sample
contains ODR violation:

//sample.h
const double num = 10.;

inline double fun()
{
    return num * num;
}

//main.cpp
#include "sample.h"

int main()
{
   double d = fun();
}

//s1.cpp
#include "sample.h"

void g()
{
    double dd = fun();
}

Here, I have two a definitions of fun in main.cpp and s1.cpp and they
use const object (linkage is internal, so, these are two different
objects) and these objects ARE NOT of integral or enumeration type. a)
So, is this an ODR violation? b)Why does standard limit constants to
integral and enumeration types?

What about objects like string literals? A string literal is an l-
value, so, if I have:

//sample.h

inline char * fun()
{
    return "aaa";
}

//main.cpp
#include <iostream>

#include "sample.h"

void g();

int main()
{
   void * p = fun();
   std::cout<<p<<std::endl;
   g();
}

//s1.cpp
#include <iostream>

#include "sample.h"

void g()
{
   void * p = fun();
   std::cout<<p<<std::endl;
}

Do I have an ODR violation again ? (with one of my compilers I have
two different pointers).

c) Should standard specify such cases or not?
And the last question - if standard restrict types of constants, which
can be referred (only integral and enumeratos, not floats) what about
floating point literals in expressions in definitions?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Greg Herlihy <greghe@pacbell.net>
Date: Tue, 29 May 2007 23:40:21 CST
Raw View
On May 29, 10:05 am, tpochep <tpoc...@mail.ru> wrote:
> 3.2 of ISO/IEC 14882 specifies the one definition rule. Item 5
> describes which entities can have more than one definition in
> different translation units. And:
>
> [citation]
> - each definition of D shall consist of the same sequence of tokens;
> and
> - in each definition of D, corresponding names, looked up according to
> 3.4, shall refer to an entity defined within the definition of D, or
> shall refer to the same entity, after overload resolution (13.3) and
> after matching of partial template specialization (14.8.3), except
> that a name can refer to a const object with internal or no linkage if
> the object has the same integral or enumeration type in all
> definitions of D, and the object is initialized with a constant
> expression (5.19), and the value (but not the address) of the object
> is used, and the object has the same value in all definitions of D;
> and .... (parts about overloaded operators, default argumenst and
> implicitly-defined constructors are skipped)
> [/citation]
>
> So, first of all, if I understand correctly, the following sample
> contains ODR violation:
>
> //sample.h
> const double num = 10.;
>
> inline double fun()
> {
>     return num * num;
>
> }
>
> //main.cpp
> #include "sample.h"
>
> int main()
> {
>    double d = fun();
>
> }
>
> //s1.cpp
> #include "sample.h"
>
> void g()
> {
>     double dd = fun();
>
> }
>
> Here, I have two a definitions of fun in main.cpp and s1.cpp and they
> use const object (linkage is internal, so, these are two different
> objects) and these objects ARE NOT of integral or enumeration type. a)
> So, is this an ODR violation?

No. The definition of "num" does not violate the One Definition Rule
since - as you noted - the two definitions define two different "num"
objects (each with internal linkage). In order to violate the ODR, a
program must define the -same- object more than once. For example:

    // sample.h
    extern const double num = 10.0;

Now a program that includes sample.h more than once will end up with
multiple definitions of the same "num" variable - which in turn would
violate the ODR because the num variable is not of an integral or
enumeration type.

> b)Why does standard limit constants to
> integral and enumeration types?

It does not. It is the case that the Standard allows only those
variables with an integral or enumeration type to be defined multiple
times (and provided that certain conditions are met). But there is no
prohibition against a program that includes the same definition
multiple times - provided that each object so defined is a distinct
object.

> What about objects like string literals? A string literal is an l-
> value, so, if I have:
>
> //sample.h
>
> inline char * fun()
> {
>     return "aaa";
>
> }

A string literal within an inline function is always the same object
and therefore should always have the same address (see    7.1.2/4). In
any event, the ODR does not apply to a string literal since it is not
a "variable, function, class type, enumeration, type or
template." [   3.2/1]

Greg



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: James Kanze <james.kanze@gmail.com>
Date: Thu, 31 May 2007 14:28:17 CST
Raw View
On May 30, 7:40 am, Greg Herlihy <gre...@pacbell.net> wrote:
> On May 29, 10:05 am, tpochep <tpoc...@mail.ru> wrote:
> > 3.2 of ISO/IEC 14882 specifies the one definition rule. Item 5
> > describes which entities can have more than one definition in
> > different translation units. And:

> > [citation]
> > - each definition of D shall consist of the same sequence of tokens;
> > and
> > - in each definition of D, corresponding names, looked up according to
> > 3.4, shall refer to an entity defined within the definition of D, or
> > shall refer to the same entity, after overload resolution (13.3) and
> > after matching of partial template specialization (14.8.3), except
> > that a name can refer to a const object with internal or no linkage if
> > the object has the same integral or enumeration type in all
> > definitions of D, and the object is initialized with a constant
> > expression (5.19), and the value (but not the address) of the object
> > is used, and the object has the same value in all definitions of D;
> > and .... (parts about overloaded operators, default argumenst and
> > implicitly-defined constructors are skipped)
> > [/citation]

> > So, first of all, if I understand correctly, the following sample
> > contains ODR violation:

> > //sample.h
> > const double num = 10.;

> > inline double fun()
> > {
> >     return num * num;
> > }

> > //main.cpp
> > #include "sample.h"

> > int main()
> > {
> >    double d = fun();
> > }

> > //s1.cpp
> > #include "sample.h"

> > void g()
> > {
> >     double dd = fun();
> > }

> > Here, I have two a definitions of fun in main.cpp and s1.cpp and they
> > use const object (linkage is internal, so, these are two different
> > objects) and these objects ARE NOT of integral or enumeration type. a)
> > So, is this an ODR violation?

> No. The definition of "num" does not violate the One Definition Rule
> since - as you noted - the two definitions define two different "num"
> objects (each with internal linkage).

But "fun" does, because the two definitions refer to different
variables.  (The "one definition rule" is rather a misnomer
here, since it is actually talking about things that must be
defined in every translation unit which uses them.  The point
being, of course, that every definition must be equivalent.)

> In order to violate the ODR, a
> program must define the -same- object more than once.

There are several ways to violate the ODR:

 -- define an object or a non-inline function more than once in
    the program (not the case here),

 -- define anything else (including non-inline functions) more
    than once in a single translation unit (not the case here
    either), or

 -- provide different definitions for the same thing in
    different translation units.

His question resolved around the latter, and what the standard
considers "different definitions".  Were the type of num and the
return type of fun int, his code would be legal, because the
standard allows using the value of integral constants here, even
though the names bind to different objects.  The standard
doesn't allow it for floating point constants, and that was his
question.

The only reason I can think of is that the standard doesn't
require the compiler to do floating point evaluation at compile
time, so traditionally, you can't use floating point constants
as freely as you can integral constants.  Whether that is a good
reason, or a sufficient reason (or even the actual reason, for
that matter), I don't know.

    [...]
> > b)Why does standard limit constants to
> > integral and enumeration types?

> It does not.

Again, reread his question.  The liberty to refer to constants
which are in fact variables with internal linkage in the same
inline function (or class definition, or enum definition) is
explicitly limited to integral constants.  The fact that fun()
uses a floating point constant makes it undefined behavior.

> It is the case that the Standard allows only those
> variables with an integral or enumeration type to be defined multiple
> times (and provided that certain conditions are met).

The standard doesn't allow *any* variables to be defined more
than once.  The rules are: objects (i.e. variables) and
non-inline functions, once in the entire program, and classes,
enumerations, inline functions, and pretty much everything where
templates are involved, once per translation unit, with the
restriction that the definitions must be "equivalent" (and the
standard then goes on to define exactly what it means by
"equivalent").  (Curiously, I can't find any mention one way or
the other with regards to references.  I'd say that that was a
defect in the standard.)

> > What about objects like string literals? A string literal is an l-
> > value, so, if I have:

> > //sample.h

> > inline char * fun()
> > {
> >     return "aaa";
> > }

> A string literal within an inline function is always the same object
> and therefore should always have the same address (see    7.1.2/4). In
> any event, the ODR does not apply to a string literal since it is not
> a "variable, function, class type, enumeration, type or
> template." [   3.2/1]

It's an object, so the ODR would apply.  Except that there's no
"definition" anywhere---it's an object without a name.  (And as
you say, a string literal within an inline function---provided
the function has external linkage---is the same object, just as
a static variable within the function would be.)

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]