The following two codes behave as expected:
char* test1 = new char[20]{"abc"};
cout << test1;
Outputs: abc
int size = 20;
char* test1 = new char[size]{'a','b','c'};
cout << test1;
Outputs: abc
But, the following code behaves unexpectedly in gcc and MSVC, while not in clang:
int size = 20;
char* test1 = new char[size]{"abc"};
cout << test1;
Outputs: random values
Why does it not output abc like the other examples?
This is clearly a GCC and MSVC bug, although I could not find an existing bug report for it. Clang seems to handle it properly.
Note that there exists wording to cover this case in [expr.new] p8:
If the expression in a noptr-new-declarator is present, it is implicitly converted to
std::size_t. The value of the expression is invalid if
- [...]
- the new-initializer is a braced-init-list and the number of array elements for which initializers are provided (including the terminating
'\0'in a string-literal ([lex.string])) exceeds the number of elements to initialize.
What you are doing is expected and valid; the expression size is present, and "abc" only provides an initializer for four elements (including the terminating '\0'), which does not exceed the 20 elements you're constructing.
The initialization follows the rules in [dcl.init.string], which covers both "abc" and {"abc"}. The remaining 16 elements of the array should be zero.
You should consider using std::string or performing the initialization in two steps:
new char[size]{}, leaving everything zero initiallystd::memcpy the string literal into the char*As commented, I agree with the answer given by Jan Schultke.
Though this is a valid and good question pointing at a probable bug in compiler implementations, it is worth mentioning that the actual usage of this would be quite rare, for the following reasons:
There is no reason to allocate the array for a size that may be smaller than required. If the size is smaller than the string literal provided (including the terminating '\0') this would be a runtime error, which throws a runtime exception for both gcc and clang.
We can allocate the array to the exact required size, by simply not providing the size:
auto test1 = new char[]{"abc"}; // allocation of 4 chars
In case we want for some reason to calculate the size, it should better be calculated it at compile time, to get compilation error instead of runtime exception, for too small size. Here is an example:
#define STR "abc" // may change
// we don't support strings longer than 4 chars and don't want to trim
// compilation error if STR size is bigger than 4
constexpr size_t max_size = 5;
constexpr size_t size = std::min(sizeof(STR), max_size);
// (std::min is constexpr since C++14)
auto test1 = new char[size]{STR};
Cases where the size would not be known at compile time would be quite rare, but can happen, for example:
#define STR "abc" // may change
size_t size = getSizeFromDB();
assert(size >= sizeof(STR));
auto test1 = new char[size]{STR};
Or:
#define STR "abc" // may change
size_t min_size = getMinSizeFromDB();
size_t size = std::max(sizeof(STR), min_size);
auto test1 = new char[size]{STR};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With