how can I convert a constat value into a non constant variable? - c++

I have this code:
PARAMS Params;
Params.pwchFileName = wide.c_str() ;
But I a getting this error:
a value of type "const wchar_t *" cannot be assigned to an entity of type "wchar_t *"
How can make this assignment?

You could, with extreme caution, use a const_cast:
const_cast<wchar_t*>( wide.c_str());
But the are other issues here: if wide is a std::string then the results of c_str() are only valid for as long as wide is in scope and has not been changed in any way. Even if you conform to this, then a consumer of PARAMS could modify the string buffer which would give you undefined behaviour.
The best thing to do here is to use strcpy to take a deep copy of the string buffer, remembering to delete that buffer once you're done with it.

The only way of making a non-constant value from a constant one that would be safe in all contexts is to make a copy:
Params.pwchFileName = new char[wide.size()+1];
strcpy(Params.pwchFileName, wide.c_str());
...
// when you are done with the copy, delete it:
delete[] Params.pwchFileName;

You can convert it forcefully by casting away constness using :-
Params.pwchFileName = const_cast<wchar_t*>( wide.c_str() );
But use const_cast when you have no other choice.
Be careful, writing into that object invokes undefined behavior.

Related

Is it good practice to pass `char []` to a function which accepts `std::string&`

I am not facing any issues with below code but is it good practice to pass char [] to a function which accepts std::string& as a parameter
const char* function(std::string& MyString)
{
MyString = "Hello World";
return MyString.c_str();
}
int main()
{
char MyString[50];
/*
*Is it good practice to cast like this?
*what possible issues i could face because of this casting?
*/
function((std::string)MyString);
std::cin.get();
return 0;
}
This simply won't work because it will require creation of temporary std::string which can not be bound to l-value reference. Even if function took a reference to std::string const creation of temporary would have an impact of performance. So depending on nature of the function it may be a good idea to add an overload that accepts a pointer to a c-string as well. Alternatively, if function is not going to modify the string you can make it accept std::string_view so it can handle both std::string and c-strings.
No, it is bad practice, as the cast has no effect; a std::string can be constructed from a char * with a non-explicit constructor, so you can remove the cast and you'll get exactly the same code (just with an implicit construction instead of an explicit cast).
Now as written, you'll get an error (at least with a non-broken compiler), as you can't pass a temporary object to a non-const lvalue reference. But if you change the function to take a const std::string &, it will work just fine.
Also bad practice is returning the char * you get by calling std::string::c_str() -- this pointer will only be valid as long as the string object is not modified or destroyed -- so the returned pointer will become invalid (dangling) as soon a the temp you passed as an argument was destroyed. If you were to save that returned pointer in a local variable in main and then try to do something with it (like printing it), that would be undefined behavior.
In short passing char[] to function accepting string is common practice (from C). And it is not bad. The explicit cast is not good here. The function also is not good, as it not accept passing char[] ...

Disable warning "deprecated conversion from string constant to 'char*' [-Wwrite-strings]"

I have these two lines in my code:
RFM2G_STATUS result;
result = RFM2gOpen( "\\\\.\\rfm2g1", &rH );
I get the error message:
"warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
result = RFM2gOpen( "\\\\.\\rfm2g1", &rH );"
Actually I can not modify it to
const RFM2G_STATUS result;
because RFM2G_STATUS is pre-defined in another file and does not accept const before. Is there another way to disable this warning message?
Like the message says, conversion from const char* to char* (which C++ inherited from ancient C language which didn't have const) has been deprecated.
To avoid this, you can store the parameter in a non-const string, and pass that to the function:
char parameter[] = "\\\\.\\rfm2g1";
RFM2G_STATUS result;
result = RFM2gOpen( parameter, &rH );
That way you avoid the ugly casts.
You seem to be absolutely sure that RFM2gOpen does not modify the input string, otherwise you would have undefined behavior in your code as it stands now.
If you are sure that the input data will not be written to, you can const_cast the constness away safely:
result = RFM2gOpen(const_cast<char*>("\\\\.\\rfm2g1"), &rH );
Again, this is only safe if the routine does not write to the input string, ever, otherwise this is undefined behavior!
If you are not completely sure that this method will never write to the character array, copy the string to an std::vector<char> and pass the .data() pointer to the function (or use a simple char array as Bo Persson suggests, that would most likely be more efficient/appropriate than the vector).
One possible fix is:
RFM2gOpen(const_cast<char*>("\\.\rfm2g1"), &rH);
This may cause a runtime fault if RFM2gOpen tries to modify the string.
The following is less likely to cause a memory fault, but it still undefined behavior:
std::string s("\\.\rfm2g1");
RFM2gOpen(const_cast<char*>(s.c_str()), &rH);
To be fully conformant you need to copy the "\.\rfm2g1" to a mutable buffer. Something like:
char *s = alloca(strlen("\\.\rfm2g1")+1);
strcpy(s, "\\.\rfm2g1");
RFM2gOpen(s, &rH);
The real fix, of course, is for RFM2gOpen to be updated to take a const char*.
It would seem that the function RFM2gOpen() expects a non-const char* as first parameter (see here), as it can sometimes happen with legacy API's (or API's written by lazy coders), and string litterals are of type const char*
so a deprecated implicit conversion is happening (getting rid of the const qualifier).
If you're *100% sure that the function won't modify the pointed-to memory, then and only then can you just put an explicit conversion, e.g. const_cast<char*>("\\\\.\\rfm2g1") or (C-style) (const char*)"\\\\.\\rfm2g1"

no conversion operator for string class

I am reading about STL string class. It is mentioned as below
STL string class chooses not to define conversion operators, but rather use the c_str() and data() methods for directly accessing the memory. The STL purposely does not include implicit conversion operators to prevent misuse of raw string pointers.
My question is
c_str() returns const char* pointer and still user can modify string value. Am I right?
What does the author mean by "to prevent misuse of raw string pointers"? Please explain, preferably with an example.
Thanks!
No, you cannot use the return value of std::string::c_str() to
modify the string. Trying to do so is undefined behavior. And
the problem was (and still is) the lifetime of the pointer
returned by std::string::c_str(). It becomes invalid if the
string is destructed, or if any non-const function is called on
the string. The issues are things like:
char const* s = string1 + string2;
// s is invalid here.
vs.
char const* s = (string1 + string2).c_str();
// s is invalid here.
In the first case, it's easy to make the mistake, without
realizing it, so the committee decided to not have implicit
conversion, so that this would be illegal. In the second case,
you have to really want to.

C++ const cast, unsure if this is secure

It maybe seems to be a silly question but i really need to clarify this:
Will this bring any danger to my program?
Is the const_cast even needed?
If i change the input pointers values in place will it work safely with std::string or will it create undefined behaviour?
So far the only concern is that this could affect the string "some_text" whenever I modify the input pointer and makes it unusable.
std::string some_text = "Text with some input";
char * input = const_cast<char*>(some_text.c_str());
Thanks for giving me some hints, i would like to avoid the shoot in my own foot
As an example of evil behavior: the interaction with gcc's Copy On Write implementation.
#include <string>
#include <iostream>
int main() {
std::string const original = "Hello, World!";
std::string copy = original;
char* c = const_cast<char*>(copy.c_str());
c[0] = 'J';
std::cout << original << "\n";
}
In action at ideone.
Jello, World!
The issue ? As the name implies, gcc's implementation of std::string uses a ref-counted shared buffer under the cover. When a string is modified, the implementation will neatly check if the buffer is shared at the moment, and if it is, copy it before modifying it, ensuring that other strings sharing this buffer are not affected by the new write (thus the name, copy on write).
Now, with your evil program, you access the shared buffer via a const-method (promising not to modify anything), but you do modify it!
Note that with MSVC's implementation, which does not use Copy On Write, the behavior would be different ("Hello, World!" would be correctly printed).
This is exactly the essence of Undefined Behavior.
To modify an inherently const object by casting away its constness using const_cast is an Undefined Behavior.
string::c_str() returns a const char *, i.e: a pointer to a constant c-style string. Technically, modifying this will result in Undefined Behavior.
Note, that the use of const_cast is when you have a const pointer to a non const data and you wish to modify the non-constant data.
Simply casting will not bring forth an undefined behavior. Modifying the data pointed at, however, will. (Also see ISO 14882:98 5.2.7-7).
If you want a pointer to modifiable data, you can have a
std::vector<char> wtf(str.begin(), str.end());
char* lol= &wtf[0];
The std::string manages it's own memory internally, which is why it returns a pointer to that memory directly as it does with the c_str() function. It makes sure it's constant so that your compiler will warn you if you try to do modifiy it.
Using const_cast in that way literally casts away such safety and is only an arguably acceptable practice if you are absolutely sure that memory will not be modified.
If you can't guarantee this then you must copy the string and use the copy.; it's certainly a lot safer to do this in any event (you can use strcpy).
See the C++ reference website:
const char* c_str ( ) const;
"Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.
A terminating null character is automatically appended.
The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only guaranteed to remain unchanged until the next call to a non-constant member function of the string object."
Yes, it will bring danger, because
input points to whatever c_str happens to be right now, but if some_text ever changes or goes away, you'll be left with a pointer that points to garbage. The value of c_str is guaranteed to be valid only as long as the string doesn't change. And even, formally, only if you don't call c_str() on other strings too.
Why do you need to cast away the const? You're not planning on writing to *input, are you? That is a no-no!
This is a very bad thing to do. Check out what std::string::c_str() does and agree with me.
Second, consider why you want a non-const access to the internals of the std::string. Apparently you want to modify the contents, because otherwise you would use a const char pointer. Also you are concerned that you don't want to change the original string. Why not write
std::string input( some_text );
Then you have a std::string that you can mess with without affecting the original, and you have std::string functionality instead of having to work with a raw C++ pointer...
Another spin on this is that it makes code extremely difficult to maintain. Case in point: a few years ago I had to refactor some code containing long functions. The author had written the function signatures to accept const parameters but then was const_casting them within the function to remove the constness. This broke the implied guarantee given by the function and made it very difficult to know whether the parameter has changed or not within the rest of the body of the code.
In short, if you have control over the string and you think you'll need to change it, make it non-const in the first place. If you don't then you'll have to take a copy and work with that.
it is UB.
For example, you can do something like this this:
size_t const size = (sizeof(int) == 4 ? 1024 : 2048);
int arr[size];
without any cast and the comiler will not report an error. But this code is illegal.
The morale is that you need consider action each time.

Deprecated conversion from string const. to wchar_t*

Hello I have a pump class that requires using a member variable that is a pointer to a wchar_t array containing the port address ie: "com9".
The problem is that when I initialise this variable in the constructor my compiler flags up a depreciated conversion warning.
pump::pump(){
this->portNumber = L"com9";}
This works fine but the warning every time I compile is anoying and makes me feel like I'm doing something wrong.
I tried creating an array and then setting the member variable like this:
pump::pump(){
wchar_t port[] = L"com9";
this->portNumber = port;}
But for some reason this makes my portNumber point at 'F'.
Clearly another conceptual problem on my part.
Thanks for help with my noobish questions.
EDIT:
As request the definition of portNumber was:
class pump
{
private:
wchar_t* portNumber;
}
Thanks to answers it has now been changed to:
class pump
{
private:
const wchar_t* portNumber;
}
If portNumber is a wchar_t*, it should be a const wchar_t*.
String literals are immutable, so the elements are const. There exists a deprecated conversion from string literal to non-const pointer, but that's dangerous. Make the change so you're keeping type safety and not using the unsafe conversion.
The second one fails because you point to the contents of a local variable. When the constructor finishes, the variable goes away and you're pointing at an invalid location. Using it results in undefined behavior.
Lastly, use an initialization list:
pump::pump() :
portNumber(L"com9")
{}
The initialization list is to initialize, the constructor is to finish construction. (Also, this-> is ugly to almost all C++ people; it's not nice and redundant.)
Use const wchar_t* to point at a literal.
The reason the conversion exists is because it has been valid from early versions of C to assign a string literal to a non-const pointer[*]. The reason it's deprecated is that it's invalid to modify a literal, and it's risky to use a non-const pointer to refer to something that must not be modified.
[*] C didn't originally have const. When const was added, clearly it should apply to string literals, but there was already code out there, written before const existed, that would break if suddenly you had to sprinkle const everywhere. We're still paying today for that breaking change to the language. Since it's C++ you're using, it wasn't even a breaking change to this language.
Apparently, portNumber is a wchar_t * (non-const), correct? If so:
the first one is wrong, because string literals are read-only (they are const pointers to an array of char usually stored in the string table of the executable, which is mapped in memory somewhere, often in a readonly page).
The ugly, implicit conversion to non-const chars/wchar_ts was approved, IIRC, to achieve compatibility with old code written when const didn't even existed; sadly, it let a lot of morons which do not know what const correctness means get away with writing code that asks non-const pointers even when const pointers would be the right choice.
The second one is wrong because you're making portNumber point to a variable allocated on the stack, which is deleted when the constructor returns. After the constructor returns, the pointer stored in portNumber points to random garbage.
The correct approach is to declare portNumber as const wchar_t * if it doesn't need to be modified. If, instead, it does need to be modified during the lifetime of the class, usually the best approach is to avoid C-style strings at all and just throw in a std::wstring, that will take care of all the bookkeeping associated with the string.