A case against direct initialisation — the sequel


A few days ago, I wrote about why I consider the commonly seen rule to prefer direct initialisation over copy initialisation false advice.

Sometimes, you feel something, based on your experience, and can’t quite pinpoint it, or recall where the feeling comes from. Yet, you’re perfectly certain it makes sense. I thought I had collected enough reasons to explain why I don’t like direct initialisation (with one argument, you don’t have much choice with more than one :)), but as you can see from the comments, not everyone agrees they’re sufficient.

Today, I recalled a fourth reason to despise direct initialisation. Try the following program in Qt 3:

#define QT_NO_CAST_ASCII
#include <qstring.h>

int main() {
    QString s1 = "foo";
    QString s2( "bar" );
    return 0;
}

You would rightfully expect that both of the statements in main() fail to compile. After all, by defining QT_NO_CAST_ASCII, I (thought I) disabled the const char* → QString conversion for good. Sure enough, that’s what happens for the first statement. But the compiler always tries to make sense of your feeble scribblings into a text editor, and in this case, it found that it could make the second statement compile by going via std::string(const char*) and QString(std::string). Oops.

Of course, this is really a bug in QString, as the QString(std::string) constructor should have been under QT_NO_CAST_ASCII protection, too. But given that even the Trolls managed to let that one slip through, before you throw the first stone, consider whether you yourself would have managed to call that bug.

To summarise: If you use direct initialisation, T t(u), you effectively allow the compiler to use two user-defined conversions to go from a U u to a T. The mediator type is not visible in the actual source code. With copy initialisation, T t = u, only one user-defined conversion is allowed (as usual), and it must either be U::operator T(), or T(U).

I don’t know about you, but I don’t like my compiler second-guessing me at every opportunityinitalisation, and I would hate for it to make an error of mine compile by inserting a double conversion via an expensive third type. So, I take my compiler on the short leash and give it copy initialisation statements wherever possible.

About marcmutz
Marc Mutz is a Senior Software Engineer, Trainer, and Consultant with KDAB.

6 Responses to A case against direct initialisation — the sequel

  1. Peter says:

    Seems fixed in 4.6.

    But isn’t it better than disabling the std::string ctor to make the ctor explicit when the macro is set ?


    #ifdef QT_NO_CAST_ASCII
    explizit
    #endif
    QString(const std::string&);

    • marcmutz says:

      Yes, it’s fixed in Qt 4. Qt 3 didn’t have (m)any explicit constructors, probably due to compiler limitations.

      That said, making the QString(std::string) constructor explicit doesn’t help in this case, because that one is explicitly called in the source. It’s the const char* → std::string conversion that is implicit, and std::string(const char*) isn’t explicit (by design).

      • Peter says:

        Ah, OK.

        I would love a GCC option to disable implicit casts. But I assume then no existing code would compile,
        so a warning would already help a lot ( but would also produce much “warning noise”).

        Maybe such a compiler flag could be added to clang, the only readable compiler code.

      • The User says:

        Well, C++ has weak typing, for a lot of cases implicit casts allow much more elegant code…

      • The User says:

        I think a QString-constructor behaving like QString::fromUtf8 would be just fine…

  2. Calvin Culus says:

    This is a case against macros, not against direct initialization.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: