0

When declaring and using static const integrals, I find it convenient and natural to use the object reference I'm working with to access the variable, rather than fully-qualifying it with the class name. I'm wondering if there is a downside to this? Take for example:

class MyLongClassNameIdRatherNotHaveEverywhere {
public:
    static const int Len = 6;
    //...
    void otherInterestingThings();
    void someWorkToDo();
};

int main() {
    MyLongClassNameIdRatherNotHaveEverywhere *lcn = new MyLongClassNameIdRatherNotHaveEverywhere;
    lcn->someWorkToDo();
    cout << "the length is: " << lcn->Len << endl;
    delete lcn;
    return 0;
}

Notice the lcn->Len... it's really a constant, and in fact if lcn were null, lcn->Len would still compile and run just fine. I could have written MyLongClassNameIdRatherNotHaveEverywhere::Len there instead, which certainly makes it more obvious (to me at least) that this is a constant. Are there other drawbacks?

mark
  • 5,269
  • 2
  • 21
  • 34
  • 1
    *"in fact if lcn were null, this still compiles and runs just fine"* That doesn't make it legal. It's undefined behavior to do that. – jrok Jul 31 '13 at 13:19
  • @jrok: No, it is not. You are not accessing the object, just using the object type to access a static member of the class. The pointer is *not* dereferenced and there is no undefined behavior involved. – David Rodríguez - dribeas Jul 31 '13 at 13:22
  • @DavidRodríguez-dribeas Do we mean the same thing? I meant `X* lcn = nullptr; lcn->foo;` kind of thing. – jrok Jul 31 '13 at 13:23
  • Note that `((MyLongClassNameIdRatherNotHaveEverywhere*)0)->Len` is not undefined behavior, it is 6. – mark Jul 31 '13 at 13:25
  • @jrok: You can use `obj.x` and `objptr->x` to access a `static` member `x`. The syntax allows it, and regardless of what it looks like it does *not* access the object. It is just an uncommon way of typing `decltype(obj)::x` (that predates `decltype`) – David Rodríguez - dribeas Jul 31 '13 at 13:27
  • 2
    @jrok: After reviewing the wording in the standard I think you are right. While the member is not part of the object, the standard requires that the expression *is* evaluated, in this case that (I understand) means dereferencing the pointer (even if the object is never accessed) and that is either undefined behavior or close enough not to want to do it :) – David Rodríguez - dribeas Jul 31 '13 at 13:33
  • 1
    @DavidRodríguez-dribeas From what I read in 5.2.5 in n3337, expression `E1->E2` is converted to `(*(E1)).E2` and both sub expressions are evaluated even if the result is not neccesary to determine the result of entire expression (see sub-text 64 on the same page). Surely that means `nullptr` gets dereferenced? EDIT: ninja'd :) – jrok Jul 31 '13 at 13:35
  • I'll point out that it's not being dereferenced in either MSVC or GNU compilers... perhaps it's just being "optimized out"? – mark Jul 31 '13 at 13:36
  • 1
    @mark Probably. It's one of those UB's that'll just work in practice. – jrok Jul 31 '13 at 13:36
  • Here's another thing to consider: look up how the `offsetof` macro is defined. Here's Microsoft's in stddef, exactly what I'm talking about: `(size_t)&reinterpret_cast((((s *)0)->m))`... doesn't seem to me undefined behavior would be part of the standard definitions...? – mark Jul 31 '13 at 14:09
  • @mark That's a [known issue](http://stackoverflow.com/questions/6433339/does-the-offsetof-macro-from-stddef-h-invoke-undefined-behaviour). Compiler writers have the freedom to use all the UB and black magic they want (and define it for their particular platform) as long as they implement the correct observable behavior. The user code doesn't have that freedom. – jrok Jul 31 '13 at 14:33

1 Answers1

1

Apart from weirdness, I can see a drawback in case operator -> is overloaded... Scope resolution operator :: btw, cannot be overloaded.

Karadur
  • 1,226
  • 9
  • 16