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) toint
over the single conversion from aNULL
pointer constant toconst 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.
-
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.
-
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.
-
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.
-
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!
-
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 bothchar
andwchar_t
... except (at least as far as I could tell) actually making it work forwchar_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 forchar
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 subclassedstreambuf
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.
-
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.
-
The standard library containers were never meant to be inherited from to begin with!
wrote a subclass of basic_streambuf
The
basic_streambuf
is not a container. It is an abstract base class you are supposed to derive.
-
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.
-
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.
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'tclass A {}; class B: private A {}; A* a = new B;
.
-
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…”?
-
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.
-
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.
-
Good find. But now that you quoted it, I can't fix it because it would make you look like a liar.
-
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 frombasic_string
instead ofstring
, 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.
-
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!