I've got this function:
I call to that function like this:Code:int lortu_word_MCR(char* synset);
And I get this error:Code:std::string str;
...
lortu_word_MCR(str.c_str());
invalid conversion from `const char*' to `char*'
Why?
Printable View
I've got this function:
I call to that function like this:Code:int lortu_word_MCR(char* synset);
And I get this error:Code:std::string str;
...
lortu_word_MCR(str.c_str());
invalid conversion from `const char*' to `char*'
Why?
Because converting from const something to something is invalid. :) You need to build a char array, copy the content of the string, pass it to the function and then delete the array.
Because the string::c_str() function is defined this way, that it returns a non-modifyable C-String.
The easiest solution is to change your function lortu_word_MCR to take an argument of type std::string&, if the function really modifies its argument, or of type const std::string& or const char* if it doesn't.
If that is not possible, you have create temporarily a char*, e.g. by using strdup function.
You've got at least 2 options:
1. change:to:Code:int lortu_word_MCR(char* synset);
2. change:Code:int lortu_word_MCR(const char* synset);
to:Code:lortu_word_MCR(str.c_str());
In case your function really needs to change the contents of the string, then you shouldn't use the above, but instead to make a copy of the string before and after the function call.Code:lortu_word_MCR(const_cast<char *>(str.c_str()));
Regards,
Bornish, the second option will not work. If the string object was initially created as a const string - in that case removing the const-ness leads to undefined behaviour. Regards.
Again, you're so wrong... it will probably work and it is not undefined behaviour... it's just that is defined by the programmer who wrote the bloody code!Quote:
Originally Posted by exterminator
It seems that you've never had to write code with "special" constrains like mixing modules for which you don't have sources, where processing speed was most important requirement. If you can't modify the prototype of the function and neither the declaration of the string, fastest way is to cast out the const... which isn't a programming error if you KNOW it's safe, and also COMMENT it properly.
But then again, it is only my oppinion, and I might've misunderstood the requirement.
Cheers,
:D Why do you think I am wrong? And why do you think I am wrong "again"? :D I cannot understand that. :confused:Quote:
Again, you're so wrong... it will probably work and it is not undefined behaviour... it's just that is defined by the programmer who wrote the bloody code!
It seems that you've never had to write code with "special" constrains like mixing modules for which you don't have sources, where processing speed was most important requirement. If you can't modify the prototype of the function and neither the declaration of the string, fastest way is to cast out the const... which isn't a programming error if you KNOW it's safe, and also COMMENT it properly.
But then again, it is only my oppinion, and I might've misunderstood the requirement.
Well, rules are rules... that is how the things are defined.. it has nothing to do with what I have done or what I am doing or what I would be doing as far as programming is concerned. And you should be least worried about that for me.
I haven't had the pleasure of working with those "special" constraints but I still know that what I have said is correct .. (because it's not my opinion... but Herb sutter's ;) and probably in the standards as well)... I just wish if you had really asked me why I said that instead of quoting me "wrong".
You opinion isn't very helpful for the OP (and many viewers) in that case - they would be sitting infront of a crashed program wondering about the reason if they accept your suggestion... debugging...
You possibly have misunderstood me this time as well like you did ;) when you talked of polymorphism with static members of your class. Well, that's all I have to say. Take care. Best regards :).
If you can't change the prototype ( aka don't have the source-code ) how would you KNOW that it is safe to cast away constness ? ( Allright there could be a comment in the header saying "this is non const but just for fun". )Quote:
Originally Posted by Bornish
Kurt
const_cast can be used with any pointer to const-declared-objects or other objects.
And, it leads to undefined behavior, if, and only if, the pointer is effectively used to modify a const-object.
As Bornish said, some third-party functions don't use const correctly (or don't use const at all), so there are many functions that don't modify at all the object, but are declared as using a pointer to non-const.
In that case, it is perfectly valid, and does not lead to undefined behavior, to use const_cast (that is the purpose of const_cast).
However, note that const_cast must only be used in the case, the new pointer is not used to modify the object, or if we know that the original object was not declared with a const qualifier.
Quote:
Originally Posted by ISO C++
Thus:
But:Code:void Modify(const int *px)
{
const_cast<int*>(px)=42;
}
int main()
{
const int x;
int y;
Modify(&x);// undefined behaviour
Modify(&y);
return 0;
}
Bornish described this valid construct.Code:#include <iostream>
std::size_t ConstIncorrectStrlen(char* str)
{
char* p=str;
while(*p!='\0') ++p;
return p-str;
}
int main()
{
const char* str="hello world!";
std::cout<<ConstIncorrectStrlen(const_cast<char*>(str)); // Valid
}
That type of construct is uncommon in well written projects that don't use any third-party librairies, but can still be used:
For example, when overloading an accessor to a container (for example operator[]):
"const T&operator[](size_type) const" can be implemented in term of "T&operator[](size_type)".
It is useful if the code is complex, because it avoids having to maintain twice the same piece of code.
Okay, I apologize.. :blush: I had overlooked this statement of his.. which is what I was trying to refer to:
Quote:
Originally Posted by Bornish
I am not quite sure about this. You cannot modify the non-const object through the pointer or reference to the const object of the same type, pointing to it (non-const object) but you can surely modify the object through the pointer or reference got after the const_cast<> over that pointer or reference to make it mean as a pointer or reference to an object (now non-const since we cast away the const) pointing to the original non-const object got from casting away the pointer or reference to the const object initially pointing to it. So I am not sure if your first example with the modify function is correct. Here is an example from the same section of the standard that suffices what I said...Quote:
Originally Posted by Superkoko
The part in italics is what I am referring to. The const-qualified access path cannot be used to modify a non-const declared object but a non-const access path (got from a const_cast of a const-qualified access path) can surely be used to do that. Regards.Code:const int ci = 3; // cvqualified (initialized as required)
ci = 4; // illformed:attempt to modify const
int i = 2; // not cvqualified
const int* cip; // pointer to const int
cip = &i; // okay: cvqualified access path to unqualified
*cip = 4; // illformed: attempt to modify through ptr to const
int* ip;
ip = const_cast<int*>(cip); // cast needed to convert const int* to int*
*ip = 4; // defined: *ip points to i, a nonconst object
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
True, but the question remains: How do you know that the passed object is under no circumstances modified.Quote:
Originally Posted by SuperKoko
So I certainly would never recommend using const_cast in any mission-critical software. Don't think it is easy to test if it works or not, as the function that is called may store a non-const static pointer to the passed object and modify it much later. You never know.
- You have access to the source code (in which case the question arises, why you don't correct the interface)
- The function is in fact so simple that it would illogical to modify the passed object (in which case the arises, why you do not write it yourself instead of using a buggy library)
treuss : the third-party library may be quite complex but well documented.
In that case, the documentation would say if the data is modified or not.
How about using "&str[0]" instead of "const_cast<char *>(str.c_str())"?
&str[0] does not guarantee that the string is null-terminated. Depending on the implementation of std::string it might not be.Quote:
Originally Posted by googler
Honestly, I find this scenario highly unlikely. Why would the interface state that it needs a modifyable object (or character string) and the documentation would state that it does not modify it. Could mean that eitherQuote:
Originally Posted by SuperKoko
But of course nothing is impossible...
- The programmer wrote the incorrect interface on purpose, in which case I would not trust the quality of the library and not use it
- The programmer did not pay much attention to the interface definition, in which case I would doubt that he payed much attention to implementation details, so I would also not trust the quality of the library and not use it.
I'm curious then how c_str() could possibly guarantee that the string is null-terminated. After all, it's a const function, so presumably does not modify the internal representation of the string. Its documentation indicates that it does not make a copy of the string either (or else why would it not have a non-const version). The way I see it in any practical implementation, the null must always be there tagged as an extra character at the end after the formal length.Quote:
Originally Posted by treuss
Why cant an implementation that does not internally use a null-terminated string copy the string data into a null-terminated string that is returned by c_str()?Quote:
Its documentation indicates that it does not make a copy of the string either (or else why would it not have a non-const version).
From roguewave documentation for basic_string:Quote:
Originally Posted by googler
I could not find a relevant section from the standards.. but for c_str it is guaranteed to returns a traits::eos() appended at the end.. here: (from standard)Code:basic_string (const charT * s,
const Allocator& a = Allocator());
Constructs a string containing all characters in s up to, but not including, a traits::eos() character.
Also, it is not necessary that the internal representation of the sequence as for a basic_string and a char[] would be the same. I mean it does support random access operator (with string[i+1] being the next character in the sequence after string[i] as does for char_string[i+1]) but it is not necessary that it will have contiguous allocation as is expected for a character array or a C-style string. The called function has no way of knowing the internal representation of the controlled sequence .. and would hence not be correct... Use c_str(). Regards.Code:const charT* c_str() const;
Returns: A pointer to the initial element of an array of length size() + 1
whose first size() elements equal the corresponding elements of the string
controlled by *this and whose last element is a null character specified by
traits::eos().
Does it remember the pointer to the copy it made? If it does, it's violating the const contract of the function. If it doesn't, you have a memory leak.Quote:
Originally Posted by laserlight
More to the point, the description of c_str() and data() (under the Requires paragraphs) indicates that they wanted these functions to be able to return a pointer to the internal representation of the string. If they didn't, there would be no reason to return a "const char*" instead of a "char*" and require that the buffer be immutable. I mean, if you're going to waste space and make a copy anyway, you could as easily make your own copy without using c_str(). Plus, it would stand to reason that if it makes a copy, there would at the very least be a non-const version of c_str() that creates a mutable duplicate in addition to the one that creates an immutable duplicate. That's why I don't think they ever intended for these functions to be making duplicates.
It must own the null-terminated string, obviously. Depending on how its done, I dont see it "violating the const contract of the function". In any case, even if the implementation were to change the internal string representation, the logical constness of the string need not change.Quote:
Does it remember the pointer to the copy it made? If it does, it's violating the const contract of the function.
I disagree. I think that it allows for an implementation that returns a pointer to the internal representation of the string. The C++ Standard doesnt mandate the internal representation, only the external interface.Quote:
the description of c_str() and data() (under the Requires paragraphs) indicates that they wanted these functions to be able to return a pointer to the internal representation of the string. If they didn't, there would be no reason to return a "const char*" instead of a "char*" and require that the buffer be immutable.
...with the difference, that c_str() guarantees the string to be null-terminated, while data does not. If they both were meant to return a pointer to the internal data buffer, there would not be the need for two functions.Quote:
Originally Posted by googler
What about an implementation, that only adds the null if c_str() is called? One could argue, that this would be a violation of the const definition of c_str(), but as the modification would be basically invisible from outside, I don't see it like that.Quote:
Originally Posted by googler
Firstly: The "const contract" is a high-level conceptual contract which specifies that a const method must not modify how the object will publically behaves in next calls to other methods. That is why mutable fields don't break that contract, if used correctly.Quote:
Originally Posted by googler
Secondly: If the string is implemented as containing a pointer to the data, this data is not const! I mean, even without const_cast you can modify a pointer within a const structure (the pointer has the const attribute but not the pointed data).
I think exactly the opposite.Quote:
Originally Posted by googler
If the standard required a specific representation it could have made the function return a char*.
But, since the implementation may be quite complex (for example, the string could be implemented as a list of bunch of memory), it is still possible for the implementation to provide a c_str function which copies all the data in a buffer, set a hidden pointer to point to that buffer in the string class, and return that pointer, and, then any modification of the string object would make the string object free the buffer (which is no more a correct representation of the string), and set the hidden pointer to NULL.
If a char* was returned, programmers could think that they are allowed to modify the buffer and that changes would be reflected to the real string, what is actually impossible with some implementations of strings.
Another example of std::string implementation that could not return a char*, is the Rogue Wave's implementation which uses a Copy-On-Write algorithm. Thus, the modification of one char* returned by a str() member would modify all other strings referring to the same data.
Even with naive implementations of std::string, putting a null-terminator only when c_str() is called, seems quite wise, to me.
Note that there could be a solution to permit usage of raw character array to access/modify data of a string.
This solution is to provide a lock method and an unlock method:
With that mechanism, it would be possible for any implementation, to allocate a buffer, when lock is called, and to copy all the string data to it, and then to commit all modifications and free the buffer, when unlock is called.Code:char* lock(); // returns a buffer to the string data that can be used to access/modify the string data.
// after a call to lock, you would not be able to access any function of std::string that could modify the string, otherwise behavior would be undefined.
void unlock(char* bufferThatWasReturnedByLock); // ensure that all changes made to the buffer are commited, and "unlocks" the string, allowing normal usage of string modifications methods.
lock and unlock functions could be fast for contiguous-non-COW implementations of std::string, and still work on other implementations.
However, that would be rarely useful.
That is why, c_str() is sufficient for almost all purposes.
Yes, it is unlikely nowadays, but the const keyword didn't existed in K&R C of the first edition of The C Programming Language (in 1978).Quote:
Originally Posted by treuss
Yes, I know that it is antediluvian, but the const keyword was not used in portable programs until 1989, and even after 1989, I guess that a few compilers were still not supporting the const keyword.
So, if the library is very old, it may be possible.
Of course, now we are in the third millenium, and a second ISO C standard is used...
I found another interesting tidbit in the standard
So it seems that the standard specifically envisions these so-called const member functions modifying the internal structure of string, and lumps them in with non-const member functions.Quote:
Originally Posted by C++ standard, section 21.3
Thanks for the history lesson ;). I admit, I was not aware that there was a life before const.Quote:
Originally Posted by SuperKoko
There are too many 3rd party libraries out there that are not const-correct. Tibco Rendezvous, which I used in 2004, is among them. It is most annoying.
We should have a campaign.
Your alternative to using const-cast is to use vector<char> internally then pass &v[0] which is non-const as long as your vector itself isn't const.
Hi all! Looks like const gave a lot of headache to many of you.
Couldn't reply sooner 'cause was a bit hectic at work lately, so I've cumulated my replies in this post.
treuss:
- I recall a positive rating on your first post because was faster than mine and entirely correct. Will accept that you don't agree with my post but will not appreciate your negative rating with this reason.
- There are times when I'm simply told which libs to use and don't have the luxury to choose. Hell, one project I had was having the sole purpose of integrating a library into a certain environment. When I had doubts about a function implementation in that library, I could contact someone from the company that wrote it, but requesting changes to it was not "in the budget" and also meant updating several major existing clients. Conclusion: cast the bloody thing and move on to meet the deadline.
exterminator:
- My honest advice is to think outside the box once in a while. As much as we want to believe (me too) that "rules" are entirely described in "standards"... well, aren't.
- I suppose implementing polymorphism through patching virtual tables at runtime would be unacceptable, but I still love to do it.
- Last thing to clarify: indeed, you've reformulated same statement you've overlooked in my first post... but did sounded like a big No-No, and that is why I've replied you were wrong... wrong to say should never be used... because will not work (it worked for me many times)
ZuK:
- I'm very happy for you not having to work with "lazy" programmers (aren't we all?) which don't care too much about const / non-const params, but if I have to call a function that needs a filename to load some data and its parameter is defined as "char *", I would use const_cast without any doubt.
SuperKoko:
- Thanks a bunch for your post! I really liked that part saying "that is the purpose of const_cast", and appreciate your effort. Once again, many thanks!
Best regards to everyone,
Both c_str() and data() must return contiguous buffers and they must be stored in within the string because the caller is not required to delete the returned pointer.
Therefore they can invoke "lazy evaluation" and have a mutable member. The fact that c_str() must put a 0 at the end of the data will also be of consequence where the buffer was not previously long enough to contain it.
So these two calls could invalidate your iterator.
Knowing that you have a string that contains a contiguous buffer of data and wanting to pass that buffer for write, you could technically use the evil const_cast on it. That might be something you would actually do in a performance-critical situation. vector<char> has the drawback of not using char_traits and therefore does not optimise the data copying. (You can optimise char_traits for unsigned char easily enough, by the way).
I would not want to see const_cast in my code unless it's hidden away somewhere.
A number, frequently stated by IT analysts, is that only about 20% of all software projects finish successfully. The other 80% exceed time or budget or both or get aborted. What you are writing is a good illustration of this: Not enough time and/or budget planned to ensure the quality of the libraries that are included - it comes down to the programmer to get out running software - the programmer uses const_cast's and hopes that they work.Quote:
Originally Posted by Bornish
Granted: In most cases const_casts will work. Just like not checking if malloc succeeded will work in most cases and many other things.
In short: I cannot blame any programmer for using const_casts in his programs to overcome old or buggy libraries, but but I stand to the point that it is not correct way to go.
Thank you Bornish for your comments. I will work on them but this needs to come to an end... I had enough of it.. I guess we all know what we must do as and when the need arises.. as for the OP's problem.. I am sure it would have been solved by now!
Off topic - but still... ;) : (it looks like a Civil war to me in here)
:D .. Best regards to all. :wave:Code:What we've got here is failure to
communicate.
Some men you just can't reach...
So, you get what we had here last week,
which is the way he wants it!
Well, he gets it!
N' I don't like it any more than you men.
The quote is actually from the movie "Cool Hand Luke", which is nothing about Civil Wars but more a typical Anti-Hero play ;) Maybe we could end this discussion with an hard-boiled-egg-eating content, though. :wave:Quote:
Originally Posted by exterminator
Really? May be.. but I picked it up from GnR - Civil War.. okay.. now I will stop or else I may be thrown out of here by one of the mods for off-topic posts... :D :wave:Quote:
Originally Posted by treuss
**EDIT** - I checked.. you are right :wave: :thumb:
treuss is correct! Ask Paul Newman if you don't believe us. :D
The quote is actually from "Cool Hand Luke" (1967) and was depicted from the movie's soundtrack by GnR as a recording, with exactly the same strange voice, accent and intonation of the prison gardian. In fact, GnR even made a video for their song in which they used clips from "Cool Hand Luke".
Trailer: Stuart Rosenberg - Cool Hand Luke
Enjoy,