Home > C++11 > Uniform Initialization Failure?

Uniform Initialization Failure?

On our latest distributed system project, we’ve decided to use some of the C++11 features provided by GCC 4.7. Right off the bat, I happily started using the “uniform initialization” feature, the auto keyword, range-for loops, and in-class member initializers.

While incorporating uniform initialization all over my crappy code, I either stumbled into a compiler bug or a flaw in my understanding of the feature. I don’t know which is the case, and that’s why I’m gonna ask for your help figuring it out in this “normal” blog post.

Behold the code that the compiler explodes on:

But Mr. Compiler, I’m trying to initialize a non-const reference (std::mutex& mtx_) lvalue with an rvalue of the exact same same type, another non-const reference (std::mutex& m). WTF?

Next, observe the change I had to make to satisfy the almighty compiler:

I’m bummed that I had to destroy the “elegance” (LOL!) of the product code by replacing the C++11 brace pair with the old style parenthesis pair of C++03.

Since little things like this tend to consume me, I explored the annoyance further by writing some little side test programs. I found that the compiler seems to barf every time I try to initialize any reference type via a brace pair – so the problem is not std::mutex specific.

So, I’m asking for your help. Is it a compiler bug, or a misunderstanding on my part?

Update A (12/1/12)

I’ve come to the conclusion that the issue is indeed a compiler bug. While searching for the cause, I found the following paper and set of initializer list examples on Bjarne Stroustrup‘s web site:

BS Init

According to the man himself, my exploding code should compile cleanly, no?

Update B (12/1/12)

After further research, I’ve flip-flopped. Now I don’t think it’s a problem with the compiler. It’s simply that the std::mutex class is not designed to support an initializer list (of one)? In order to support uniform initialization, I think a class must be explicitly designed to provide it via some sort of constructor syntax that I haven’t learned yet. Thus, unless all the classes used in a program explicitly provide initializer list support, the program must use “mixed initialization” in order to compile. If this is true, then bummer. Uniform initialization doesn’t come “for free” with C++11 – which is what I erroneously thought.

Update C 12/5/12

After yet more research and coding on this annoying issue, I discovered that whether or not brace style initialization works for references is indeed type specific. As the example below shows, brace style initialization compiles fine for a reference to a plain old int.

boguis ref

In the process of experimenting, I also discovered what I think is a g++ 4.7.2 compiler bug:

Base Error

Note that in this case, I’m trying to brace-init a member of type Base, not a reference to Base. There’s something screwy going on with brace initialization that I don’t understand. Got any advice/insight to share?

Categories: C++11 Tags:
  1. Geoff
    February 26, 2013 at 3:10 am

    I’ve been playing with this with g++ 4.7.2 all day. I’ve read lots and haven’t been able to work out for certain whether it’s a compiler bug or a defect in the standard. My view is that a reference is a reference regardless of what it is referencing (just as a pointer is a pointer whatever it points at), so initializer lists should work consistently regardless of the type.

    What seems to be happening (as a result of something the standard says or once said) is that the compiler is trying to bind the reference being initialized to a temporary created via the copy constructor of the type using the input reference (initializer item) as the source … which is just silly (or certainly far from intuitive). I’ve seen this specifically because one of the types I’m playing with has the copy constructor deleted and so I get to see the error about trying to use it.

    So far my only solution has been mixed initialization (using brackets to initialize references, braces for the rest) – and a comment in the code so I can come back and fix it if/when someone sorts out what is supposed to happen. I’ve yet to test the result of some of this, I new to playing with C++11 and still trying to adapt.

    • February 26, 2013 at 4:40 am

      Thanks for diving in Geoff. It may be an bug in the standard, but I think it’s just some subtlety that I still don’t understand.

      • Geoff
        February 26, 2013 at 5:17 am

        Try this to see what I mean:

        class AType {
        public:
            AType();
            AType(const AType&) = delete;
        };
        
        class BType {
            explicit BType(const AType& a) : x_{a} {}
        private:
            const AType& x_;
        };
        

        When BType uses the const AType& member as above it tries to use the AType copy constructor and you get the error: “use of deleted function”.

        When you BType uses just the non-const AType& you get the error about invalid initialization – because it would need to bind to a temporary which is not allowed.

        That is: the initializer is trying to create a temporary when the initializer list contains a reference – even when the destination is also a reference, at that seems like a real mistake rather than a subtlety.

      • February 26, 2013 at 12:20 pm

        I duplicated your experiment and got the same compile error result as you with GCC 4.7.

  1. No trackbacks yet.

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 )

Facebook photo

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

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: