Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing std::array<char,x> member in constructor using string literal. GCC bug?

The following example initializing a std::array <char, N> member in a constructor using a string literal doesn't compile on GCC 4.8 but compiles using Clang 3.4.

#include <iostream>
#include <array>

struct A {
  std::array<char, 4> x; 
  A(std::array<char, 4> arr) : x(arr) {}
};


int main() {
    // works with Clang 3.4, error in GCC 4.8.
    // It should be the equivalent of "A a ({'b','u','g','\0'});"
    A a ({"bug"});
    for (std::size_t i = 0; i < a.x.size(); ++i)
        std::cout << a.x[i] << '\n';

    return 0;
}

On first impression it looks like a GCC bug. I feel it should compile as we can initialize a std::array<char, N> directly with a string literal. For example:

std::array<char, 4> test = {"bug"}; //works

I would be interested to see what the Standard says about this.

like image 282
Ricky65 Avatar asked Feb 04 '14 14:02

Ricky65


1 Answers

Yes, your code is valid; this is a bug in gcc.

Here's a simpler program that demonstrates the bug (I've replaced std::array<char, 4> with S and got rid of A, as we can demonstrate the bug just in function return (this makes the analysis simpler, as we don't have to worry about constructor overloading):

struct S { char c[4]; };
S f() { return {"xxx"}; }

Here we have a destination object of type S that is copy-initialized (8.5p15) from the braced-init-list {"xxx"}, so the object is list-initialized (8.5p17b1). S is an aggregate (8.5.1p1) so aggregate initialization is performed (8.5.4p3b1). In aggregate initialization, the member c is copy-initialized from the corresponding initializer-clause "xxx" (8.5.1p2). We now return to 8.5p17 with destination object of type char[4] and initializer the string literal "xxx", so 8.5p17b3 refers us to 8.5.2 and the elements of the char array are initialized by the successive characters of the string (8.5.2p1).

Note that gcc is fine with the copy-initialization S s = {"xxx"}; while breaking on various forms of copy- and direct-initialization; argument passing (including to constructors), function return, and base- and member-initialization:

struct S { char c[4]; };
S f() { return {"xxx"}; }
void g(S) { g({"xxx"}); }
auto p = new S({"xxx"});
struct T { S s; T(): s({"xxx"}) {} };
struct U: S { U(): S({"xxx"}) {} };
S s({"xxx"});

The last is particularly interesting as it indicates that this may be related to bug 43453.

like image 146
ecatmur Avatar answered Nov 13 '22 02:11

ecatmur