const char* to char* conversion

P

Perro Flaco

this -->

The function parameter is declared improperly. In other words, the
function
doesn't really need to modify the data, i.e. it doesn't really need a
'char*'
and a 'const char*' would work just as well. The better way to resolve
the
problem in this case would be to change the function's parameter
declaration
from 'char*' to the more appropriate 'const char*', assuming this is
possible.
Otherwise, the 'const_cast' of 'c_str()' result to 'char*' type
(mentioned by
others) would work, but it is rather ugly.


Noah Roberts ha escrito:
 
W

werasm

Andrey said:
When some function need a 'char*' (as opposed to 'const char*') as an input,
this usually means one of two things:

1) The function needs to modify the data pointed by that 'char*' pointer. In
this can what you are trying to do is simply useless, because strings of
'std::string' type cannot be modified through the pointer returned by 'c_str()'.

Functions that modify the data pointed by 'char*' parameter are not compatible
with 'std::string' at all. The only safe way around is to convert the
'std::string' to a standalone modifiable zero-terminated C-style string, pass it
to the function and then convert the results back to 'std::string'.

2) The function parameter is declared improperly. In other words, the function
doesn't really need to modify the data, i.e. it doesn't really need a 'char*'
and a 'const char*' would work just as well. The better way to resolve the
problem in this case would be to change the function's parameter declaration
from 'char*' to the more appropriate 'const char*', assuming this is possible.
Otherwise, the 'const_cast' of 'c_str()' result to 'char*' type (mentioned by
others) would work, but it is rather ugly.

There is a third reason:

Some older "C" APIs require char* even though the string will not be
modified. When this is the case, a const_cast will suffice.

As example, take for instance the vxWorks function lptDevCreate:

Declaration as stated in their documentation.
STATUS lptDevCreate
(
char * name, /* name to use for this device */
int channel /* physical channel for this device (0 - 2) */
);

Now, when calling this (over which you have no control), there is
nothing wrong with doing the following:

void createLptDevice( const std::string& name, eChannelType channel )
{
STATUS result(
lptDevCreate( const_cast<char*>(name.c_str()),
static_cast<int>(channel) ) );
//...if( STATUS == ERROR ) throw etc...
}

I must mention that I would in such cases write wrapper functions (like
the one above) that only do the const_cast in one place. Often related
wrappers would reside in a wrapper class that becomes responsible for
the resource.

Kind regards,

Werner
 
V

Victor Bazarov

Sgt. York said:
I would go out of my way to avoid this. I would use a temporary
despite the performance hit.

What "temporary" would you use? The proper way, of course, is to
allocate necessary memory in free store, copy the string contents
there, and then give the pointer to the function:

char* p = new char[MyString.size() + 1];
memcpy(p, MyString.data(), MyString.size() + 1);
somefunction( blah, blah, p );
delete[] p;

I hate it when the library is not const-correct and I have to resort
to this...

V
 
W

werasm

Victor said:
What "temporary" would you use? The proper way, of course, is to
allocate necessary memory in free store, copy the string contents
there, and then give the pointer to the function:

char* p = new char[MyString.size() + 1];
memcpy(p, MyString.data(), MyString.size() + 1);
somefunction( blah, blah, p );
delete[] p;

I don't agree here (see my other post). Also refer to Scott Meyers'
Item 21 of Effective C++ (the incorreclty declared strlen example,
where he states its OK to use const_cast in this/that situation).
I hate it when the library is not const-correct and I have to resort
to this...

Yes me too, but what you did is in some cases an overkill (when you
know for a fact that the function will not modify the string, despite
it not being const correct). This is most often very obvious. When not,
I would take your route - I would try to get rid of memory by scoping
though - would use boosts scoped_array typically.

boost::scoped_array<char> p( new char[MyString.size()+1] );
std::copy( MyString.begin(), MyString.end(), p.get() );
//personally, I hate memcpy because of it lack of type safety...
p[MyString.size()] = '\0';
someFunction( p.get() );
//No need to delete, but you'd know...

....Of course, knowing that someFunction was in actual fact strlen,
declared in BadLib, this would become.
 
N

Noah Roberts

Perro said:
Noah Roberts ha escrito:

[top posting fixed]
The function parameter is declared improperly. In other words, the
function
doesn't really need to modify the data, i.e. it doesn't really need a
'char*'
and a 'const char*' would work just as well. The better way to resolve
the
problem in this case would be to change the function's parameter
declaration
from 'char*' to the more appropriate 'const char*', assuming this is
possible.
Otherwise, the 'const_cast' of 'c_str()' result to 'char*' type
(mentioned by
others) would work, but it is rather ugly.

I see. I couldn't tell wtf you were talking about because of your top
posting. You would be more understandable if you stopped doing that.

http://lipas.uwasa.fi/~ts/http/quote.html
 
S

Sgt. York

Victor said:
Sgt. York said:
I would go out of my way to avoid this. I would use a temporary
despite the performance hit.

What "temporary" would you use? The proper way, of course, is to
allocate necessary memory in free store, copy the string contents
there, and then give the pointer to the function:

char* p = new char[MyString.size() + 1];
memcpy(p, MyString.data(), MyString.size() + 1);
somefunction( blah, blah, p );
delete[] p;

I hate it when the library is not const-correct and I have to resort
to this...

V

Yes, that's what I meant, the temporary in this case being the variable
"p". Bad choice of wording on my part, since temporary means something
else in c++.
 
S

Sgt. York

werasm said:
Victor said:
What "temporary" would you use? The proper way, of course, is to
allocate necessary memory in free store, copy the string contents
there, and then give the pointer to the function:

char* p = new char[MyString.size() + 1];
memcpy(p, MyString.data(), MyString.size() + 1);
somefunction( blah, blah, p );
delete[] p;

I don't agree here (see my other post). Also refer to Scott Meyers'
Item 21 of Effective C++ (the incorreclty declared strlen example,
where he states its OK to use const_cast in this/that situation).
I hate it when the library is not const-correct and I have to resort
to this...

Yes me too, but what you did is in some cases an overkill (when you
know for a fact that the function will not modify the string, despite
it not being const correct). This is most often very obvious. When not,
I would take your route - I would try to get rid of memory by scoping
though - would use boosts scoped_array typically.

How is this "most often very obvious?" I'm given a compiled library and
a header file. How do I used that to determine that "very obviously" a
non-const pointer is not being used to modify memory?
 
D

Default User

werasm wrote:

Some older "C" APIs require char* even though the string will not be
modified. When this is the case, a const_cast will suffice.

As example, take for instance the vxWorks function lptDevCreate:

Declaration as stated in their documentation.
STATUS lptDevCreate
(
char * name, /* name to use for this device */
int channel /* physical channel for this device (0 - 2) */
);


I'm always very wary of passing the pointer from c_str() to any library
function, const or not. That's because of this:

"Requires: The program shall not alter any of the values stored in the
array. Nor shall the program treat the returned value as a valid
pointer value after any subsequent call to a non-const member function
of the
class basic_string that designates the same object as this."


If that library function stores off the pointer, or passes it around,
it may become invalid due to affects elsewhere in the code.

The best idea all-around is to make a copy of the thing.



Brian
 
N

Noah Roberts

Default said:
If that library function stores off the pointer, or passes it around,
it may become invalid due to affects elsewhere in the code.

Well, you better know things like that anyway. If it stores it
somewhere or passes it off then you still have similar problems because
you need to know when you can delete it.

char* is just plain problematic. Nothing you do will make it safe or
easy to work with.
 
J

Jim Langston

Sgt. York said:
werasm said:
Victor said:
What "temporary" would you use? The proper way, of course, is to
allocate necessary memory in free store, copy the string contents
there, and then give the pointer to the function:

char* p = new char[MyString.size() + 1];
memcpy(p, MyString.data(), MyString.size() + 1);
somefunction( blah, blah, p );
delete[] p;

I don't agree here (see my other post). Also refer to Scott Meyers'
Item 21 of Effective C++ (the incorreclty declared strlen example,
where he states its OK to use const_cast in this/that situation).
I hate it when the library is not const-correct and I have to resort
to this...

Yes me too, but what you did is in some cases an overkill (when you
know for a fact that the function will not modify the string, despite
it not being const correct). This is most often very obvious. When not,
I would take your route - I would try to get rid of memory by scoping
though - would use boosts scoped_array typically.

How is this "most often very obvious?" I'm given a compiled library and a
header file. How do I used that to determine that "very obviously" a
non-const pointer is not being used to modify memory?

A function such as
void display_text( char * Text, int X, int Y );

Even though it's not const correct, it better not change the char array.
That should be fairly obvious unless the library developer is really out of
whack.
 
S

Sgt. York

Jim said:
Sgt. York said:
werasm said:
Victor Bazarov wrote:

What "temporary" would you use? The proper way, of course, is to
allocate necessary memory in free store, copy the string contents
there, and then give the pointer to the function:

char* p = new char[MyString.size() + 1];
memcpy(p, MyString.data(), MyString.size() + 1);
somefunction( blah, blah, p );
delete[] p;

I don't agree here (see my other post). Also refer to Scott Meyers'
Item 21 of Effective C++ (the incorreclty declared strlen example,
where he states its OK to use const_cast in this/that situation).

I hate it when the library is not const-correct and I have to resort
to this...
Yes me too, but what you did is in some cases an overkill (when you
know for a fact that the function will not modify the string, despite
it not being const correct). This is most often very obvious. When not,
I would take your route - I would try to get rid of memory by scoping
though - would use boosts scoped_array typically.
How is this "most often very obvious?" I'm given a compiled library and a
header file. How do I used that to determine that "very obviously" a
non-const pointer is not being used to modify memory?

A function such as
void display_text( char * Text, int X, int Y );

Even though it's not const correct, it better not change the char array.
That should be fairly obvious unless the library developer is really out of
whack.

Exactly. I am not confident from reading a function's name alone that
it does not modify my pointer. I would consider the developer "out of
whack" for not declaring the pointer const in the parameter list to
begin with if there is no intent to modify the memory. Some of the
Win32 API functions spring to mind ...
 
W

werasm

Sgt. York said:
How is this "most often very obvious?" I'm given a compiled library and
a header file. How do I used that to determine that "very obviously" a
non-const pointer is not being used to modify memory?

Well, in the case of strlen, the documentation might simply state this.
In other cases such as those mentioned, the documentation also states
this. The legacy library simply has not changed with the times, and is
still usable. It may also be obvious from experience, of course.

Many libraries existed and are used that were created in pre-const
days, unfortunately. You have two options, either pay the performance
penalty or, if you know the library - do the const_cast. The important
thing is, know why you are doing what you are doing. If you don't need
the performance gain, then use the heap.

Regards,

W
 
W

werasm

Default said:
werasm wrote:

If that library function stores off the pointer, or passes it around,
it may become invalid due to affects elsewhere in the code.

Yes, true. But then making a copy of the thing won't suffice - only a
literal or global would (perhaps a global const std::string or static -
in which case the const_cast would once again be required). Most of the
old API functions with parameters called "name" expected literals. The
only problem that you may have is that the function does not
necessarily complete synchronously. If the function has a result
indicating completion, such as strlen - or the above mentioned one, it
is safe to assume that the usage of the parameter has completed.

The fact remains, that for these unfortunate (const incorrect) APIs,
whether you create memory on the heap, or whether you const_cast c_str,
or whether you use a buffer on the stack (which is what I would prefer
over heap, BTW) - in all these cases you are likely to get failure.
Using literals or global/static consts then become your only option,
but what if your name is borne from your instance (dynamic), and is a
concatenation of various literals. Then we go back to:

1. Create copy on heap
- whack could delete it at worst void foo( char* name) { delete p;
/*fooled ya*/ }.
- whack could send it to another context (PostMessage...).
- whack could overindex...
- etc
2. Create copy on stack
- All the above still apply - obviously with undefined results.
3. Use a string.
- All the above still applies.
- In addition to this the string may not be modified - impossible for
local string BTW.
- If the string is modified by the function, then behaviour is
undefined - yes.

Alas...
For these unfortunate functions, I try to understand what the parameter
is used for, and then act accordingly. If it is used synchronously
only, and only performs reading (which I derive from the names of
parameters, return type and documentation etc), then I'm willing to go
for the const_cast. If not, well - then I'll be carefull of other
options mentioned too, as they are also error prone - especially in a
RoundRobin scheduling OS.

All said, if you're given a gun but you haven't seen one before, you
can shoot yourself! For this reason, to any newbies - I advise you
being very careful of such API's - using the most conservative
approach. const_cast is certainly less conservative.

Regards,

Werner
 
U

u.int.32.t

Perro said:
Because there are other functions that need "char*" as input, so I get
errors when I do: str1.c_str()

I would like to convert a string to a char*, or a const char* to char*.
Any advice?

Thanks!

The correct solution is to use function overloading:

#include <iostream>

void f(char *)
{
std::cout << "char *" << std::endl;
}

void f(char const * p)
{
std::cout << "char const *" << std::endl;
f(const_cast<char *>(p));
}

int main()
{
char const * x = "Hello";
f(x);
char * p = "Hello";
f(p);
}
 
V

Victor Bazarov

The correct solution is to use function overloading:

#include <iostream>

void f(char *)
{
std::cout << "char *" << std::endl;
}

void f(char const * p)
{
std::cout << "char const *" << std::endl;
f(const_cast<char *>(p));
}

int main()
{
char const * x = "Hello";
f(x);
char * p = "Hello";

While this is kinda OK for an example like yours, if I saw it in my
student's work, I'd definitely lowered the grade. Initialising
a pointer to non-const char with a literal is allowed in C++ when it
really ought to be disallowed (and all who did that in their code
had to fix their code). A [much] better way would be

char p[] = "Hello";

V
 

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

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top