deprecated conversion from string constant to 'char*'

J

Joe

When I compile the following code, I get the warning below. I have this
code in a header file outside the class. How do I get rid of this warning?

static char *myColors[] = {
"red", "white", "blue"
};

warning: deprecated conversion from string constant to 'char*'
 
S

SG

When I compile the following code, I get the warning below. I have this
code in a header file outside the class. How do I get rid of this warning?

static char *myColors[] = {
    "red", "white", "blue"

};

warning: deprecated conversion from string constant to 'char*'

....with good reason. A string literal is an lvalue of type array of
const char in C++. You're casting away const. The only reason why this
doesn't fail to compile is C compatibility.

Cheers!
SG
 
A

Alf P. Steinbach

* Joe:
When I compile the following code, I get the warning below. I have this
code in a header file outside the class. How do I get rid of this warning?

static char *myColors[] = {
"red", "white", "blue"
};

warning: deprecated conversion from string constant to 'char*'

Consider

char* p = "bah";

which should yield the same warning.

The reason is that 'p' allows you to attempt to modify a string literal.

The solution is to say that those characters are non-modifiable via this pointer,

char const* p = "bah";

In addition you may want to add a const stating that 'p' itself isn't modified
after initialization,

char const* const p = "bah";


Cheers & hth.,

- ALf
 
J

Jonathan Lee

Though I do that rarely: When I have an array of constant strings I do it
differently, is that incorrect too?

example:

--- colordefs.h--
static const unsigned int COLORNUM = 3;
static const unsigned int COLORMAXLEN = 32;
static const char ar_pszColors[COLORNUM ][COLORMAXLEN] =
{
"red", "white", "blue"};

--- colordefs.h--end


I prefer something like:

static const char * ar_pszColors[] = {"red", "white", "blue"};
static const int numColors = sizeof(ar_pszColors) / sizeof
(ar_pszColors[0]);

That way, numColors/COLORNUM doesn't have to be updated manually.

Of course, many would say to use std::vector and std::string, but
that's a whole other conversation.
 
J

James Kanze

On Aug 17, 4:38 am, "Christian Freund" <[email protected]>
wrote:
Though I do that rarely: When I have an array of constant
strings I do it differently, is that incorrect too?
example:
--- colordefs.h--
static const unsigned int COLORNUM = 3;
static const unsigned int COLORMAXLEN = 32;
static const char ar_pszColors[COLORNUM ][COLORMAXLEN] =
{
"red", "white", "blue"};
--- colordefs.h--end
I prefer something like:
static const char * ar_pszColors[] = {"red", "white", "blue"};
static const int numColors = sizeof(ar_pszColors) / sizeof
(ar_pszColors[0]);
That way, numColors/COLORNUM doesn't have to be updated manually.

Another frequent solution is to use something like:

template< typename T, size_t N >
size_t
size( T (&a)[ N ] )
{
return N ;
}

In the current standard, this can't be used in an integral
constant expression, but the next version of the standard
provides a means of supporting that. It also fails if T is a
local type. On the other hand, if instead of an array, you have
a pointer---typically, a function parameter declared as an
array---it fails at compile time, rather than just giving some
wrong value.
Of course, many would say to use std::vector and std::string,
but that's a whole other conversation.

Not really. This is a case where C style arrays are definitely
preferable to std::vector, for several reasons. The proposed
std::array and the new initialization syntax will solve some of
the problems, but unless I've missed something, there is no way
for std::array to have its dimensions calculated automatically,
and std::vector continues to require dynamic initialization
(which can introduce order of initialization issues).
 
J

Jonathan Lee

Not really.  This is a case where C style arrays are definitely
preferable to std::vector, for several reasons.

Not that I would agree with using std::vector... but I thought
the situation of "I'm updating the size of the array manually"
was screaming for someone to swoop in and recommend a container.

I'm a little disappointed that no one has :(

--Jonathan
 
N

Noah Roberts

Jonathan said:
Not that I would agree with using std::vector... but I thought
the situation of "I'm updating the size of the array manually"
was screaming for someone to swoop in and recommend a container.

Well, first off a C array IS a container...it's just a really piss poor
one for dynamic memory and is all but obsoleted by boost::array.
I'm a little disappointed that no one has :(

boost::array

Your code would change from:

static const char * ar_pszColors[] = {"red", "white", "blue"};
static const int numColors = sizeof(ar_pszColors) / sizeof
(ar_pszColors[0]);

to:

static boost::array<char const*, 3> ar_pszColors[] = {...};

"numColors" is then simply a part of your array:

int numColors = ar_pszColors.size();

The one thing I don't like, but don't think there's a way around, is
having to provide the size in the declaration. The good thing, what
makes that less problematic, is you'll get notified by the compiler if
you ever add an initializer and forget to increment the size.
 
J

James Kanze

Not that I would agree with using std::vector... but I thought
the situation of "I'm updating the size of the array manually"
was screaming for someone to swoop in and recommend a
container.
I'm a little disappointed that no one has :(

Why? In his case, the size doesn't change, and in fact, I
rather suspect that if he were to make it const correct,
everything would be const---the array is immutable. And
immutable arrays are one case where C style arrays are better
than std::vector. In fact, the only way to create his array as
an std::vector< std::string > and make it const is by
initializing the vector from a C style array.
 
J

James Kanze

Well, first off a C array IS a container...it's just a really
piss poor one for dynamic memory and is all but obsoleted by
boost::array.

Yes and no. Boost::array (which will be std::array in the next
version of the standard) does cover a lot of the remaining uses.
But one of the nice things about C style arrays is that the
compiler can calculate the size based on the initialization
list. (If I understand correctly, in the next version of the
standard, it will be possible for the initialization list to
determine the size of an std::vector, but not the size of an
std::array. An std::vector, however, has dynamic
initialization, which means that instances with static lifetime
are still subject to order of initialization issues.)
Your code would change from:
static const char * ar_pszColors[] = {"red", "white", "blue"};
static const int numColors = sizeof(ar_pszColors) / sizeof
(ar_pszColors[0]);

static boost::array<char const*, 3> ar_pszColors[] = {...};

And there's that magic number 3 in there, that has to be updated
if you change the number of elements. For 3 or 4, probably not
a big issue, but I have a number of cases where there are 20 or
30, and counting them is somewhat error prone.
"numColors" is then simply a part of your array:
int numColors = ar_pszColors.size();
The one thing I don't like, but don't think there's a way
around, is having to provide the size in the declaration. The
good thing, what makes that less problematic, is you'll get
notified by the compiler if you ever add an initializer and
forget to increment the size.

But you still have to count once, and the compiler won't say
anything if you remove one (or mis-count too high).

The next release of the standard will support something like:

std::vector< std::string > colors{ "red", "white", "blue" } ;

but that implies dynamic initialization (and thus, possible
order of initialization issues), and if I understand correctly,
this notation won't work for std::array (because you have to
mention the size as part of the type).

So there is still a use for C style arrays. My rule would be no
C style arrays with other than static lifetime, and none in a
public interface.
 
J

Jonathan Lee

I'm a little disappointed that no one has :(
Why?  In his case, the size doesn't change, [...]

Oh, it's not that his case particularly needs it. It's just
one of those things I expect in CLC++. Similarly, if someone
were using printf(), someone else would say to use cout.

Or if I were in a crowded room and said loudly "do re mi fa
so la ti...", I would expect someone to finish it. And if
no one did, I'd be a little disappointed.

--Jonathan
 
N

Noah Roberts

Jonathan said:
I'm a little disappointed that no one has :(
Why? In his case, the size doesn't change, [...]

Oh, it's not that his case particularly needs it. It's just
one of those things I expect in CLC++. Similarly, if someone
were using printf(), someone else would say to use cout.

For trivial uses of printf(), sure. There are things you can do in
printf() that don't translate to streams though, and at the moment I
can't think of them.

One might point them to boost::format though, which does translate from
printf() formatting and is type safe.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top