views:

130

answers:

2

A few simple questions.

const int gFirst;
const int gSecond;

struct Data
{
    static int First;
    static int Second;

    int first;
    int second;
};

Data data;

Is it guaranteed that the following statements are true?

1) &gFirst < &gSecond
2) &Data::First < &Data::Second
3) &data.first < &data.second

+6  A: 

The answer:

1) Not guaranteed.
   But probably.
   But the order of initialization is guaranteed.
2) No. 
   You just have the declaration here.  
   You need to to define the instances in a source file.
   Then they will behave the same way as the objects in (1).
3) Yes.
Martin York
To 1) I think the order of initialization inside one source file is guarantied. Initialization order of multiple Sourcefiles is undefined.
Markus Kull
I was sloppy with question 2 for assuming you would also initialize the data in another file in the same order as the variables are declared here. My bad. This 2. case is actually the one I'm most interested in.
zeroes00
+8  A: 

1) This result is unspecified.
2) This result is unspecified.*
3) Yes.

The relevant section in the standard is §5.9/2. Relational comparisons between the pointers p and q are only specified when:

  • p and q point to the same object or function, point to one past the end of the same array, or both are null. In this case, p <= q and p >= q are true, and p < q and p > q are false.
  • p and q point to nonstatic data members of the same object, the pointer to the later declared member compares greater. (Note, this comparison cannot be between access specifiers.)
  • p and q point to elements within the same array or one past the end of the array, the pointer to the element with the higher subscript or to one past the end of the array compares greater.
  • p and q point to data members of the same union object, in which case they compare equal.

In all other cases, the result is not specified.

*Because they are static, they (obviously) do not get the "nonstatic member" rules. They will be defined in some translation unit, and therefore are just like any other pointer. (Unspecified.)


Note! There is a way to get total ordering, and that is via std::less<void*> (and all the other comparative function objects.)

This is in §20.3.3/8:

For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not.

So while you don't know if std::less<void*>(&gFirst, &gSecond) is true or false, you are guaranteed:

std::less<void*>(&gFirst, &gSecond) ==
    std::greater<void*>(&gSecond, &gFirst);
std::less<void*>(&Data::First, &Data::Second) ==
    std::greater<void*>(&Data::Second, &Data::First);

Which can prove useful.

GMan