2

I am following a turorial and one of the answers contains the following snippet:

    private:
      char *m_data;

     public:
      HelloWorld() {
        m_data = new char[14]{"Hello, World!"};   // should work in c++14
                                          // ^ the error points here

}

which according to the author should work in c++14, yet when I try to compile I receive the following error:

"invalid conversion from 'const char*' to 'char'

Where is the problem and how to fix it?

13
  • 2
    Why are you using raw char pointers at all? Can you elaborate about a good reasoning? Commented May 25, 2017 at 19:05
  • 2
    The author of the book is unfortunately mistaken in this instance. String literals become arrays of const char, which decay into const char* Commented May 25, 2017 at 19:06
  • 1
    that is a very bad requirement. new is not recommended in C++ at all, especially not when dealing with strings. Commented May 25, 2017 at 19:07
  • 2
    @KOKO "uni requirement" Worst requirements ever. Please attend your teacher to contact me regarding that. I'll tell them they're incompetent and unuseful and why. Commented May 25, 2017 at 19:08
  • 1
    If your teacher insists on using char pointer: m_data = new char[14]{'H','e','l','l','o',',',' ','W','o','r','l','d','!'}; ... not that I would recommend this ;-) Commented May 25, 2017 at 19:14

3 Answers 3

3

The original code is supposed to work. Section C++14 [expr.new]/7.4 even explicitly mentions this exact case, to say that it's an error if the string literal is too long for the array:

The expression in a noptr-new-declarator is erroneous 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) exceeds the number of elements to initialize.

In the latest standard draft, the definition of list-initialization in [dcl.init.list]/3 says:

Otherwise, if T is a character array and the initializer list has a single element that is an appropriately-typed string literal, initialization is performed as described in that section.

(and the previous point before "Otherwise" was not triggered for this case).

Other comments mention some confusion about initialization rules. See DR 1490 - the C++11 text could be read as saying char s[4]{"abc"}; is ill-formed because it attempts to take the string literal as initializer for s[0]. However, the intent was that this code work -- any wording suggesting otherwise would be defective wording.

This was accepted as a defect, but the resolution process (DR 1467) did not complete until after the publication of C++14.

Defect resolutions are considered to retroactively replace the text they resolved; so code conforming to C++14 should use the rule as I quoted above, which is clear and unambiguous. Common sense would also use the same rule for C++11 conformance.

Sign up to request clarification or add additional context in comments.

2 Comments

In this case do you have an idea why gcc would throw an error?
@KOKO yeah, compiler bug
2

The code is valid at least according to the C++ 2017 Standard (and the C++ 2014 Standard for which a bug report was written.). It seems that the used compiler just does not support this feature. If so then copy the string literal to the allocated memory

#include <cstring>

//...
// m_data = new char[14]{"Hello, World!"};   
m_data = new char[14];
std::strcpy( m_data, "Hello, World!" );   

3 Comments

Evil strcpy()!
I agree. The problem is, it's so easy to use incorrect and create buffer overrun.
@user2079303 the author claims so
1

The tutorial is mistaken. You need to type in a literal character array initializer like this:

m_data = new char[14]{'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0'};

Remember that you have to manually add the null terminator '\0' at the end!

4 Comments

I am not so shure about the manually adding the null terminal because it works fine without '\0'.
@KOKO If you want to use it as a string (with string functions) then the null terminator is essential. If it works without it, that's luck. (as in bad luck because it is masking a bug).
I think '\0' is indeed not needed, because compiler will automatically add zero-initialization for remaining array members, if less than array length is explicitily initialized.
@zett42 Yes you are correct, unless the string is the same length as the size in which case the missing null will go unnoticed. So I think it's safer to be explicit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.