The Un-Initialization



  • Oh, how the WTFs just keep on flowing (this one was initially discovered by a coworker)...
    [code]
    // in a codebase-common header file
    #define UNDEFINED ( 0 )
    typedef int32_t dword; // this eventually becomes int
    // in some function written by a dimwit who doesn't understand C++ overloading rules
    void Dimwit_Func(/* args /)
    {
    // some gunk
    Vendor_String some_string_var = UNDEFINED;
    // more gunk that does things to some_string_var
    }
    // in Vendor_String.H
    class Vendor_String: public string
    {
    public:
    Vendor_String(const char
    s = 0);
    // other constructors that don't stand a chance of being chosen
    Vendor_String(dword num, const char* fmt = 0);
    // lots of other garbage that we don't care about
    };
    // in Vendor_String.C (don't ask me about their choice of file extensions!)
    Vendor_String::Vendor_String(dword num, const char* fmt): string()
    {
    char buf[255];
    const char* f = (fmt)? (fmt): ("%i");
    if (EOF != sprintf(buf, f, num))
    {
    assign(buf);
    }
    }
    [/code]

    So, for those of you who are don't live in C++-ville, this code was apparently a totally misinformed attempt by the dim bulbs at $vendor to 'make sure my string is initialized'. However, trying to initialize their string class with an integer 0 causes the second constructor listed in the code above to be chosen due to C++ overloading rules: the compiler has to prefer the identity conversion of int to a type typedef'ed (eventually) to int over the single conversion from a NULL pointer constant to const char * when resolving the overloaded constructor call. As a result, the dimwitted programmer is baffled when he finds out that his dimwitted function is initializing a string variable to "0". Yes, that's a string with the numeral 0 in it, put there by a totally needless sprintf() call.

    Can't you just let your compiler call the default constructor in peace for once, folks?



  • TRWTF is using 256-byte buffer for 32-bit number. No, wait, TRRWTF is subclassing std::basic_string<char> instead of making templated subclass for all basic_strings.


  • Discourse touched me in a no-no place

    I'm going to have to downgrade "doesn't understand rule interactions" to a minor WTF. But $vendor's an idiot--when I was going through this kind of problems I posted on forums where people who knew C++ better than me and were willing to help hung out.



  • That's narrow-minded.


  • Discourse touched me in a no-no place

    @chubertdev said:

    That's narrow-minded.

    I'm trying to decide if you were going for some kind of type-conversion language pun here. If so, bravo.



  • @FrostCat said:

    I'm trying to decide if you were going for some kind of type-conversion language pun here. If so, bravo.

    Thank you, kind sir. :grinning:



  • @Gaska said:

    No, wait, TRRWTF is subclassing std::basic_string instead of making templated subclass for all basic_strings.

    No, wait, TRRRWTF is subclassing std::basic_string (or any instantiation thereof) at all! The standard library containers were never meant to be inherited from to begin with!



  • @Gaska said:

    No, wait, TRRWTF is subclassing std::basic_string instead of making templated subclass for all basic_strings.

    Possibly defensible. A while back I wrote a subclass of basic_streambuf because I figured I might as well make it work for both char and wchar_t... except (at least as far as I could tell) actually making it work for wchar_t required some wide character-to-multibyte character conversions I didn't feel like figuring out how to do, and because we didn't need it anyway I just gave up and so it only works for char anyway. Aside from being silghtly closer to a helpful solution if someone does eventually need it (probably will never happen), I may as well have just subclassed streambuf directly. I can certainly imagine something similar happening here.

    (Though tarunik makes a reasonably good point about subclassing string in the first place.)



  • Well, it is possible, so there might be use cases for that, even if imaginary (see private inheritance). But deriving just to make int-to-string conversion on the fly is definitely not right.

    I like C++, mostly because there are few things that most other languages done wrong (RAII, value semantics for everything unless stated otherwise, non-virtual methods, standalone variables and functions). But it has great many misfeatures too, like implicit casts, shitty locale support, horrible boilerplate in many common tasks, etc. Currently, I'm waiting for Rust language to gain maturity, because it seems to solve most of C++'s problems without abandoning its qualities - but recently I've been worried about its development too, mainly because it lacks non-interface inheritance (and all proposals that address this seem to forget that sometimes you want to inherit from class in another module), and the developers seem to be terrible, terrible FOSStards.



  • @Gaska said:

    Well, it is possible, so there might be use cases for that, even if imaginary (see private inheritance). But deriving just to make int-to-string conversion on the fly is definitely not right.

    Even in private inheritance there are problems subclassing from std::string. The biggest issue being the std::string destructor isn't virtual, so the subclass's destructor may not be called. Eg, when doing:

    string *strPtr = new Vendor_String(12);
    delete strPtr;
    

    The Vendor_String destructor isn't called. If Vendor_String doesn't have a destructor then I guess there wouldn't be any issues... But all will go to hell if you ever want to add one.



  • @tarunik said:

    The standard library containers were never meant to be inherited from to begin with!

    @EvanED said:

    wrote a subclass of basic_streambuf

    The basic_streambuf is not a container. It is an abstract base class you are supposed to derive.



  • @Evo said:

    Even in private inheritance there are problems subclassing from std::string.

    When I mentioned private inheritance, what I meant is "there is no real reason to ever, ever do it - but since there is such language construct, there must be some reason - and since it's not real, it's imaginary". Same with subclassing STL containers. Stroustrup is a smart guy and he wouldn't put completely pointless features in his pet language.



  • @Gaska said:

    When I mentioned private inheritance, what I meant is "there is no real reason to ever, ever do it - but since there is such language construct, there must be some reason - and since it's not real, it's imaginary". Same with subclassing STL containers. Stroustrup is a smart guy and he wouldn't put completely pointless features in his pet language.

    He didn't "put" it in there, it's a direct consequence of the existence of inheritance and the fact that the standard library containers are classes. The only design decision there was not to give those containers virtual destructors: the choice for speed vs. the ability of inheriting a container. He choose for speed.
    So it's not really a language construct, it's a consequence of 2 language constructs. Private inheritance is a language construct, and yes, there will probably be some scenario's this could be useful (if a base class uses virtual functions only, probably).



  • Deriving from classes without virtual destructors is a language construct - if it was forbidden (because it's not useful except in some imaginary cases Stroustrup thought about), then no problems with uncalled destructors would exist.

    @Evo said:

    Private inheritance is a language construct, and yes, there will probably be some scenario's this could be useful (if a base class uses virtual functions only, probably).

    No there is not - because the derived class wouldn't be treated as subclass of its base class outside of its own context. You can't class A {}; class B: private A {}; A* a = new B;.


  • Discourse touched me in a no-no place

    Is it just me or is C++ really just a grab-bag of features inspired mainly by “wouldn't it be neat if we did…”?



  • @dkf said:

    Is it just me or is C++ really just a grab-bag of features inspired mainly by “wouldn't it be neat if we did…”?

    Yes, yes it is. But they don't consider UTF-8, straightforwardness, graphics, precompiled libraries and small executable size neat, so we have to work around those problems in horrible, horrible ways.

    Bonus C++ WTF: three years have passed (actually more like ten) and there's still not a single fully C++11-complaint standard library implementation.



  • @Gaska said:

    Bonus C++ WTF: three years have passed (actually more like ten) and there's still not a single fully C++11-complaint standard library implementation.

    I found the complaint. :arrow_up:



  • Good find. But now that you quoted it, I can't fix it because it would make you look like a liar.



  • @Bulb said:

    The basic_streambuf is not a container. It is an abstract base class you are supposed to derive.

    I was addressing the comment that they should have inherited from basic_string instead of string, not whether inheriting from either is a good idea in the first place. Which, you'll notice, I mentioned at the end of my first post.



  • @Evo said:

    The biggest issue being the std::string destructor isn't virtual, so the subclass's destructor may not be called.

    That's literally the only thing that I know of that's fundamentally wrong subclassing the stdlib classes. There are other traps, e.g. if you overload rather than override a function and then expect the wrong one to be called, but the virtual destructor thing is the only thing I know of that any subclass will have, and where users of the class itself have to be pretty careful.

    And even the missing virtual destructor isn't a deathblow; there are plenty of situations where it could be useful to have such a subclass where you wouldn't run into it. There's a reason that "you are extending a base class without a virtual destructor" is a warning and not an error.

    Now, it's still a bad idea, and almost everything would be better served by composition. But it's very possible to do it and do it correctly, and sometimes all the options are kind of bad so you have to pick the least bad amongst them.



  • Looking through more of their code, I'm not sure if this un-initialization is better or worse:

    [code]
    ListOVendorStrings::const_iterator iter = 0;
    [/code]

    Good luck getting that to compile!


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.