The following code produces the compilation error, invalid conversion from 'const char*' to 'char*'. Both ptrInputFileName and ptrFileName are both declared as const char*. Any suggestions on how to get this to compile? Thank you.
TextInputBuffer::TextInputBuffer(const char *ptrInputFileName)
: ptrFileName(new char[strlen(ptrInputFileName) + 1])
{
//--Copy the file name.
std::strcpy(ptrFileName, ptrInputFileName);
Obviously, you can't copy into a something pointed to by a const * - remove the const, and if that cause problems calling the constructor, you are doing something semantically invalid.
Also, your use of pseudo-hungarian makes the code difficult to read. Lose the ptr prefixes, and make the names shorter.
strcpy takes the the destination as non-const pointer char* and ptrFileName is const char*. No implicit conversion possible and I wouldn't recommend an explicit conversion. Just make ptrFileName non-const.
Use std::string.
struct TextInputBuffer {
TextInputBuffer(const char *filename)
: _filename(filename)
{}
// Explicit delete not even required as it would have been
// when you used new.
private:
std::string _filename;
};
Related
Basically I am wondering whether something like
f(const void* a){
// This is also what `(char**) a` would do behind the scenes
char** string_a_ptr {reinterpret_cast<char**>(const_cast<void*>(a))};
// ...
is possible while preserving the const qualifier.
My question came up during an exercise about C-Arrays in C++. Because of C, I had to pass a function pointer with const void* arguments. In this case it was pointing on an array of C-strings. To cast it to the correct type I had to cast the const away. Is there a way in C++ to get something like a "(const char*)*"` pointer?
I have tried out const char** (without the const_cast) which yields
reinterpret_cast from type ‘const void*’ to type ‘const char**’ casts away qualifiers
and (const*)*, which gives a syntax error
expected type-specifier before ‘(’ token
This is a purely academic question. I am aware, that the problem can be solved easier and saver using std::string and #include <algorithm>.
While I am at it, are there advantages of sometimes using C-constructions in C++ or should they always be avoided if possible? I only did some small scale exercise problems with C code in C++, but it already causes quite a few headaches and forces me to look really closely under the hood, even though I have written a fair amount of C code in my life.
Or is it would you rather recommend using the extern C qualifier and writing C code in pure C?
That would be a char* const *.
There are three places in a double pointer to put const:
const char**
Pointer, to a pointer, to a character you cannot change.
char *const *
pointer, to a pointer you cannot change, to a character.
char ** const
pointer you cannot change, to a pointer, to a character.
You can mix these to make different parts const.
I believe this is what you're looking for:
const char * const * string_a_ptr = static_cast<const char * const *>(a);
[Live example]
You could even drop the first const if you want (and it makes sense).
Explanation:
const void * a means that a points to something (void) which is const. Therefore, if you cast a to another pointer, it must also point to something that is const. In your case, you're casting it to a pointer to char*. That char* must therefore be const. The syntax for creating a constant pointer (not a pointer to a constant) is to put the const to the right of the *. Hence, char* const *.
I want to create a move constructor that takes string literal, and then move that c string to a member pointer.
The best solution I could write is giving a warning:
deprecated conversion from string constant to 'char*' [-Wwrite-strings]
CTextBlock cctb("move(H)");
^
the code:
#include <iostream>
using namespace std;
class CTextBlock
{
public:
CTextBlock(char* &&text)//move constructor
{
pText = text;
}
private:
char *pText;
};
int main()
{
CTextBlock cctb("move(H)"); //WARNING
return 0;
}
First off, the type of string literals is char const[N] (for a suitable constant N). This array can be assigned to a char const* in which case it will decay into a pointer to the first element. It cannot be converted to a char*. Prior to C++11 the conversion to char* was allowed to deal with existing code which wasn't const-correct (e.g., because it started as C code before C got const). This conversion was removed for C++11.
Question is what you actually try to achieve, though: string literals are immutable and persist for the entire life-time of the program. You can just keep as many pointers to them as you want and there is no point in moving pointers as these are entirely cheap to copy.
In your question you indicate that you want to create a move constructor but move constructors take an rvalue reference of the class they are for, e.g., this would be a move constructor for you class:
CTextBlock::CTextBlock(CTextBlock&& other)
: pText(other.pText) {
other.pText = 0;
}
(your class doesn't show any ownership semantics for the pointer pText in which case move construction doesn't really make much sense; the above code assumes that there is some ownership semantics and that a null pointer indicates that the object doesn't own anything).
Just because an argument is constrained to be an rvalue reference doesn't mean that function is a move constructor. All it implies is that the argument is an rvalue an it can reasonably be assume that it's current representation doesn't need to be retained. The string literal appears to be an rvalue because the the string literal is converted into a [temporary] pointer to the start of the array.
A constructor that gets reasonably close to allowing only literals can be realized as a template:
#include <cstddef>
#include <assert>
struct X
{
char const * str;
std::size_t len;
template <std::size_t N>
X(char const (&a)[N]) : str(a), len(N - 1)
{
assert(a[len] == '\0'); // true for string literals
}
};
It's not fool-proof, though, since it will also bind to named character arrays, and the length computation is dubious if your string also contains null values. But if you're trying to avoid accidental use of dynamic values (e.g. in an algorithm that builds strings from expressions and literal strings), this is fairly useful.
A string literal is a const char *. This is true whether or not it's used as an lvalue or an rvalue.
If you review your code again, you are, therefore, attempting to store a const char * into a char *, and that's where your compiler diagnostic is coming from. Your move constructor is taking an rvalue reference to a char *, and not a const char *. Change it to a const char *, and change the pText class member to a const char *, and what you're trying to do should work.
I'm not going to say I fully understand the idea of const correctness but let's at least say that I understand it. So, when I encountered this, I was/am stumped. Can someone please explain this to me. Consider the following code:
#include <iostream>
struct Test {
int someInt;
void * pSomething;
};
void TestFunc(Test * const pStruct) {
pStruct->someInt = 44;
pStruct->pSomething = "This is a test string"; // compiler error here
}
int main() {
Test t;
TestFunc(&t);
return 0;
}
At the point I've annotated with a comment I get this error from gcc (4.5.3 for cygwin):
foo.cpp:10:24: error: invalid conversion from `const void*' to `void*'
It's apparently something to do with the fact that the struct contains a void* because some experimentation revealed that changing the struct to:
struct Test {
int someInt;
char * pSomething;
};
produces a warning as opposed to an error. Also, leaving the structure unchanged but modifying this line to include the following cast compiles the code without warning:
pStruct->pSomething = (void*)"This is a test string"; // no error now
What I don't understand, given my understanding of const correctness, is why is the compiler emitting this error, "invalid conversion from ‘const void*’ to ‘void*’" at all? Since the const modifier on the function definition makes it so that the pointer is constant but what it points to is not, why should this be a problem? I'm assuming that there is some sort of implicit cast happening, as originally written, since the string literal would be something like const char * that must be converted to void *. That notwithstanding, the question remains since what pStruct points to is not constant.
For reference, I read up on const correctness here and here.
The error you are observing has absolutely nothing to do with const qualifier used in function declaration, or with any const qualifiers you explicitly used in your code.
The problem is the same as in the following minimal example
void *p = "Hello";
which suffers from the same error.
In C++ language the type of string literal is const char [N]. By the rules of const correctness it is convertible to const void *, but it is not convertible to void *. That's all.
A more formally correct error message would be "Cannot convert from const char [22] to void *", or "Cannot convert from const char * to void *", but apparently the inner workings of the compiler perform the conversion to const void * first (under the hood) and then stumble on conversion to void *, which is why the error message is worded that way.
Note that const correctness rules of C++ language used to include an exception that allowed one to implicitly convert string literals to char * pointers. This is why
char *p = "Hello";
compiles with a mere warning, even though it violates the rules of const correctness just like the previous example. That exception applied only to conversions to char * type, not to void * type, which is why the previous example produces an error. This special conversion has been deprecated in C++03 and removed from the language in C++11. This is why the compiler issues a warning about it. (If you switch your compiler to C++11 mode it will become an error.)
First of all, your test class and function just make things unnecessarily complex. In particular, the error has nothing to do with the const in Test * const pStruct, because this only means that pStruct must not be made to point to anything else. After all, in your own words:
the const modifier on the function definition makes it so that the
pointer is constant but what it points to is not
Here is a simplified piece of code to reproduce the problem:
int main() {
void *ptr = "This is a test string"; // error
}
As for your question,
What I don't understand, given my understanding of const correctness,
is why is the compiler emitting this error, "invalid conversion from
‘const void*’ to ‘void*’" at all? Since the const modifier on the
function definition makes it so that the pointer is constant but what
it points to is not, why should this be a problem?
Because a string literal is a char const[], "decaying" to a char const *, and the conversion to a non-constant pointer would lose the const qualifier.
This does not work for the same reason the following won't:
int main() {
int const *i; // what's pointed to by i shall never be modified
void *ptr = i; // ptr shall modify what's pointed to by i? error!
}
Or more precisely,
int main() {
int const i[22] = {}; // i shall never be modified
void *ptr = i; // ptr shall modify i? error!
}
If this was not an error, then you could use ptr to implicitly bypass the const qualifier of i. C++ simply does not allow this.
Finally, let's look at this piece of code:
pStruct->pSomething = (void*)"This is a test string"; // no error now
Again, this can be simplified and reproduced with int rather than char so as not to obfuscate the real issue:
int main() {
int const i[22] = {}; // i shall never be modified
void *ptr = (void*)i; // ptr shall modify i? ok, I'll just shut up
}
You should not use C-style casts in C++. Use one of static_cast, reinterpret_cast, dynamic_cast and const_cast to make it clear which kind of conversion should be enforced.
In this case, you'd have seen the trouble it takes to "shut up" the compiler:
int main() {
int const i[22] = {};
void *ptr = const_cast<void*>(reinterpret_cast<void const *>(i));
}
And, of course, even though this may compile without a warning, the behaviour of the program is undefined because you must not use const_cast to cast away the constness of an object originally initialised as constant.
Edit: I forgot about the whole char * C compatibility business. But this is covered in the other answers already and, to my best understanding, does not render anything in my answer incorrect.
First of all, using C style casts will break const correctness. That is the only reason that your cast "works". So don't do it. Use reinterpret_cast, which (should, I didn't test it) get you a similar error to the one you are seeing.
So "This is a test string" is a const char*. If you reference it as a void*, something could modify the contents of void* later. If you make it so you can mess with the contents of that, you're no longer const correct.
And you COULD if there was no error, shown below.
int main() {
Test t;
TestFunc(&t);
reinterpret_cast<char*>(t.pSomething)[0]='?';
return 0;
}
"blah" is an array of 5 char const. In C++11 it converts implicitly to char const*. In C++03 and earlier the literal also converted implicitly to char*, for C compatibility, but that conversion was deprecated, and it was removed in C++11.
Setting
void* p = "blah"; // !Fails.
you get the conversion sequence char const[5] → char const* → void*, where the last one is invalid and yields an error.
Setting
char* p = "blah"; // Compiles with C++03 and earlier.
with C++11 you get the same conversion as for void*, and an error, but with C++03 and earlier, since the source is a literal string you get char const[5] → char*.
I've got a couple questions that I think will be quite easy for someone with C++ experience to answer, I'll bold the quesitons for the TL;DR
Given the following code:
void stringTest(const std::string &s)
{
std::cout << s << std::endl;
}
int main()
{
stringTest("HelloWorld");
}
Hopefuly someone can point out the error in my thought process here:
Why does the parameter in stringTest have to be marked const when passed a C-Style string? Isn't there an implicit conversion to an std::string that takes place using its cstyle string constructor, therefore "s" is no longer a reference to a literal (and is not required to be const).
Furthermore, what would a cstyle string constructor look like, and how does the compiler know to invoke this upon seeing:
stringTest("HelloWorld");
Does it simply recognize a string literal to be something like a char*?
I've stumbled upon these questions while studying copy constructors. Another quick quesiton for my own clarification...
In the case of something like:
std::string s = "HelloWorld";
Is the cstyle string constructor used to instantiate a temporary std::string, and then the temporary string is copied into "s" using the string copy constructor?:
std::string(const std::string&);
Why does the parameter in stringTest have to be marked const when passed a C-Style string?
It only has to when the parameter is a reference, since a temporary std::string is constructed from the char const* you pass in and a non-const reference to a temporary is illegal.
Does it simply recognize a string literal to be something like a char*?
A string literal is a char const array, which decays to char const*. From that, the compiler infers that it should use the non-explicit constructor std::string::string(char const *) to construct the temporary.
Is the cstyle constructor used to instantiate a temporary std::string, and then the temporary string is copied into "s" using the string copy constructor?
It's a bit more complicated than that. Yes, a temporary is created. But the copy constructor may or may not be called; the compiler is allowed to skip the copy construction as an optimization. The copy constructor must still be provided, though, so the following won't compile:
class String {
String(char const *) {}
private:
String(String const &);
};
int main()
{
String s = "";
}
Also, in C++11 the move constructor will be used, if provided; in that case, the copy constructor is not required.
Does it simply recognize a string literal to be something like a
char*?
This part of the original question wasn't answered as clearly as I'd have liked. I fully endorse (and up-voted) Yossarian's answer for the rest though.
Basically, you need to understand what the compiler is doing when it sees a string literal in the code. That array of chars (as any c-style string really is) is actually stored in a completely different location than the code it's a part of (depending on the architecture, numeric literals can be stored at the location itself as part of the assembly/binary instruction). The two blocks of code here are "more or less" equivalent (ignore lack of includes or namespace declarations) :
int main(void)
{
cout << "Hello!" << endl;
return 0;
}
This is closer to what's "really" happening:
const char HELLO_STR[] = { 'H', 'e', 'l', 'l', 'o', '!', 0 };
int main(void)
{
cout << HELLO_STR << endl;
return 0;
}
Forgive me if I made an error in array init or whatever, but I think this expresses what I mean as for where the string literal is "really" stored. It's not in-line, but is an invisible constant to another part of the program where it's defined. In addition, some (most?) compilers out there also arrange the string literals "together" so that if you have the same literal used in 50 places, it only stores one of them, and all of them refer back to the same constant, saving memory.
So remember that any time you're using a string literal, you're using a const char[N] that exists "invisibly" somewhere, that is implicitly converted to const char*.
Why does the parameter in stringTest have to be marked const when passed a C-Style string?
EDIT:
Temporaries must be immutable. See larsmans comment and answer, he is right.
Simple reason:
void change(std::string& c) { c = "abc"; }
change("test"); // what should the code exactly do??
Furthermore, what would a cstyle string constructor look like, and how does the compiler know to invoke this upon seeing:
It looks up std::string for string(char*) constructor
In the case of something like:
std::string s = "HelloWorld";
Is the cstyle constructor used to instantiate a temporary std::string, and then the temporary string is copied into "s" using the string copy constructor?:
std::string(const std::string&);
No. In this exact case (TYPE variable = SOMETHING), it is the same as writing TYPE variable(SOMETHING);. So, no copying is used.
The const string & s is in this example required to invoke the constructor from the argument "HelloWorld". The constructor used is the type-conversion construction.
A string& s won't do because s is directly referencing a string object.
The type conversion is defined by something similar to
basic_string(const _CharT* __s);
With a typedef
typedef basic_string<char> string;
So the declaration would evaluate to
basic_string(const char * __s)
With the following code, if I attempt to convert a template array to std::string, instead of the compiler using the expected std::string conversion method, it raises an ambiguity resolution problem (as it attempts to call the array conversion methods):
#include <iostream>
template<typename TemplateItem>
class TestA
{
public:
TemplateItem Array[10];
operator const TemplateItem *() const {return Array;}
operator const std::string() const;
};
template<>
TestA<char>::operator const std::string() const
{
std::string Temp("");
return Temp;
}
int main()
{
TestA<char> Test2;
std::string Temp("Empty");
Temp = Test2; //Ambiguity error. std::string or TemplateItem * ?
return 0;
}
What modification do I need to make to the code in order to make it so the code correctly and implicitly resolve to the std::string conversion function? Especially given the const TemplateItem * would be treated as a null-terminated array (which it won't likely be).
First, the reason you have ambiguity: you provide both conversion to char* and conversion to std::string const, and std::string likes them both.
By the way, before getting to your question, the const in operator std::string const was once a good idea, advocated by e.g. Scott Meyers, but is nowadays ungood: it prevents efficient moving.
Anyway, re the question, just avoid implicit conversions. Make those conversions explicit. Now I answered that in response to another SO question, and someone (I believe the person was trolling) commented that C++98 doesn't support explicit type conversion operators. Which was true enough, technically, but pretty stupid as a technical comment. Because you don't need to use the explicit keyword (supported by C++11), and indeed that's not a good way to make the conversions explicit. Instead just name those conversions: use named member functions, not conversion operators.
#include <iostream>
template<typename TemplateItem>
class TestA
{
public:
TemplateItem Array[10];
TemplateItem const* data() const { return Array; }
std::string str() const;
};
template<>
std::string TestA<char>::str() const
{
return "";
}
int main()
{
TestA<char> test2;
std::string temp( "Empty" );
temp = test2.str(); // OK.
temp = test2.data(); // Also OK.
}
Cheers & hth.
I will add, after thinking about it, here's the reasoning and what should be done:
The operator const TemplateItem *(); Should be deleted.
Why? There never will be an instance where you would want implicit conversion of TestA (or any template class) to a TemplateItem array with an unknown size - because this has absolutely no bounds checking (array could be sizeof 1 or 10 or 1000 or 0) and would likely cause a crash if a calling function or class received the array with no idea what size it is.
If the array is needed, either use the operator[] for direct items, or GetArray (which would signal the user intends to pass an unknown-length array).
Retain operator const std::string. Code will compile. Possible memory issues down the line averted.
(Alf for his efforts has been selected as the 'correct' answer, although this is the more logical option)