Related
I have read this (Pasted below as well) on Wikipedia:
Following usual C convention for declarations, declaration follows use, and the * in a pointer is written on the pointer, indicating dereferencing. For example, in the declaration int *ptr, the dereferenced form *ptr is an int, while the reference form ptr is a pointer to an int. Thus const modifies the name to its right. The C++ convention is instead to associate the * with the type, as in int* ptr, and read the const as modifying the type to the left. int const * ptrToConst can thus be read as "*ptrToConst is a int const" (the value is constant), or "ptrToConst is a int const *" (the pointer is a pointer to a constant integer).
I really am not able to get a satisfying interpretation:
In which sense does it modify?
What is intended with name vs type (see the above link)?
And why should it be on the right side of const?
The const, volatile and restrict (C99 onwards) keywords are considered type qualifiers. They are an integral part of type signatures and describe additional semantics about a type.
If they appear at the topmost level of a declaration, they affect the declared identifier:
const int a = 5; // prevents modifications of "a"
int *const p = &x; // prevents modifications of "p", but not "*p"
int **const q = &y; // prevents modifications of "q", but not "*q" and "**q"
If they appear in pointer subtypes (before an asterisk), they affect the pointed-to value at the particular level of dereferencing:
const int *p = &x; // prevents modifications of "*p", but not "p"
const int **q = &y; // prevents modifications of "**q", but not "*q" and "q"
const int *const *r = &z; // prevents modifications of "**r" and "*r", but not "r"
const int *const *const s = &a; // prevents modifications of "**s", "*s" and "s"
The Wikipedia excerpt discusses two different conventions for declaring pointers:
int *p; // more common in C programming
int* p; // more common in C++ programming
I would say that the "true" convention is the first one because it works according to the syntax of the language (declarations mirror use). The asterisk in that declaration is in fact the same dereferencing operator that you would use on the pointer in normal expressions. Thus the int type is returned after applying * (indirection) on p (the pointer itself).
Also note that the ordering of type qualifiers with respect to type specifiers and other type qualifiers does not matter, so these declarations are equivalent:
const int a; // preferred
int const a; // same, not preferred
const volatile int b; // preferred
volatile const int b; // same, not preferred
volatile int const b; // same, not preferred
const int *p; // preferred
int const *p; // same, not preferred
In which sense does it modify?
Modifies in the sense that it makes it constant, meaning it can't be modifed (assigned to, or passed to a function which might modify it).
What is intended with name vs type (see the above link)?
Name means the word written in the source code here, I think.
And why should it be on the right side of const?
"Modifies name to its right" means, by example:
const char * str, here const modifies char, in other words the characters are constant, you can't modify them. You can make str point to a new char, but you still can't modify it either (at least not through str). *str = 'a'; is compiler error, str = "foo"; is ok.
char * const str, here const modifies str, in other words the value of str can't be modified. It points to some char, and you can modify that char through str, but you can't make str to point to another char. *str = 'a'; is now ok, str = "foo"; is error.
It is legal to convert a pointer-to-non-const to a pointer-to-const.
Then why isn't it legal to convert a pointer to pointer to non-const to a pointer to pointer to const?
E.g., why is the following code illegal:
char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char **ps = a; // error!
From the standard:
const char c = 'c';
char* pc;
const char** pcc = &pc; // not allowed
*pcc = &c;
*pc = 'C'; // would allow to modify a const object
Ignoring your code and answering the principle of your question, see this entry from the comp.lang.c FAQ:
Why can't I pass a char ** to a function which expects a const char **?
The reason that you cannot assign a char ** value to a const char ** pointer is somewhat obscure. Given that the const qualifier exists at all, the compiler would like to help you keep your promises not to modify const values. That's why you can assign a char * to a const char *, but not the other way around: it's clearly safe to "add" const-ness to a simple pointer, but it would be dangerous to take it away. However, suppose you performed the following more complicated series of assignments:
const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */
In line 3, we assign a char ** to a const char **. (The compiler should complain.) In line 4, we assign a const char * to a const char *; this is clearly legal. In line 5, we modify what a char * points to--this is supposed to be legal. However, p1 ends up pointing to c, which is const. This came about in line 4, because *p2 was really p1. This was set up in line 3, which is an assignment of a form that is disallowed, and this is exactly why line 3 is disallowed.
And as your question is tagged C++ and not C, it even explains what const qualifiers to use instead:
(C++ has more complicated rules for assigning const-qualified pointers which let you make more kinds of assignments without incurring warnings, but still protect against inadvertent attempts to modify const values. C++ would still not allow assigning a char ** to a const char **, but it would let you get away with assigning a char ** to a const char * const *.)
Just since nobody has posted the solution, here:
char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char * const*ps = a; // no error!
(http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17 for why)
The C++11 draft standard explains this in a note in section 4.4 which says:
[ Note: if a program could assign a pointer of type T** to a pointer
of type const T** (that is, if line #1 below were allowed), a program
could inadvertently modify a const object (as it is done on line #2).
For example,
int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; // #1: not allowed
*pcc = &c;
*pc = 'C'; // #2: modifies a const object
}
—end note ]
An interesting related question is Given int **p1 and const int **p2 is p1 == p2 well formed?.
Note the C++ FAQ also has an explanation for this but I like the explanation from the standard better.
The conforming text that goes with the note is as follows:
A conversion can add cv-qualifiers at levels other than the first in
multi-level pointers, subject to the following rules:56
Two pointer types T1 and T2 are similar if there exists a type T and
integer n > 0 such that:
T1 is cv1,0 pointer to cv1,1 pointer to · · · cv1,n−1 pointer to cv1,n
T
and
T2 is cv2,0 pointer to cv2,1 pointer to · · · cv2,n−1 pointer to cv2,n T
where each cvi,j is const, volatile, const volatile, or nothing. The
n-tuple of cv-qualifiers after the first in a pointer type, e.g.,
cv1,1, cv1,2, · · · , cv1,n in the pointer type T1, is called the
cv-qualification signature of the pointer type. An expression of type
T1 can be converted to type T2 if and only if the following conditions
are satisfied:
the pointer types are similar.
for every j > 0, if const is in cv1,j then const is in cv2,j , and similarly for volatile.
if the cv1,j and cv2,j are different, then const is in every cv2,k for 0 < k < j.
There are two rules here to note:
There are no implicit casts between T* and U* if T and U are different types.
You can cast T* to T const * implicitly. ("pointer to T" can be cast to "pointer to const T"). In C++ if T is also pointer then this rule can be applied to it as well (chaining).
So for example:
char** means: pointer to pointer to char.
And const char** means: pointer to pointer to const char.
Since pointer to char and pointer to const char are different types that don't differ only in const-ness, so the cast is not allowed. The correct type to cast to should be const pointer to char.
So to remain const correct, you must add the const keyword starting from the rightmost asterisk.
So char** can be cast to char * const * and can be cast to const char * const * too.
This chaining is C++ only. In C this chaining doesn't work, so in that language you cannot cast more than one levels of pointers const correctly.
It is legal to convert a pointer-to-non-const to a pointer-to-const.
Then why isn't it legal to convert a pointer to pointer to non-const to a pointer to pointer to const?
E.g., why is the following code illegal:
char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char **ps = a; // error!
From the standard:
const char c = 'c';
char* pc;
const char** pcc = &pc; // not allowed
*pcc = &c;
*pc = 'C'; // would allow to modify a const object
Ignoring your code and answering the principle of your question, see this entry from the comp.lang.c FAQ:
Why can't I pass a char ** to a function which expects a const char **?
The reason that you cannot assign a char ** value to a const char ** pointer is somewhat obscure. Given that the const qualifier exists at all, the compiler would like to help you keep your promises not to modify const values. That's why you can assign a char * to a const char *, but not the other way around: it's clearly safe to "add" const-ness to a simple pointer, but it would be dangerous to take it away. However, suppose you performed the following more complicated series of assignments:
const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */
In line 3, we assign a char ** to a const char **. (The compiler should complain.) In line 4, we assign a const char * to a const char *; this is clearly legal. In line 5, we modify what a char * points to--this is supposed to be legal. However, p1 ends up pointing to c, which is const. This came about in line 4, because *p2 was really p1. This was set up in line 3, which is an assignment of a form that is disallowed, and this is exactly why line 3 is disallowed.
And as your question is tagged C++ and not C, it even explains what const qualifiers to use instead:
(C++ has more complicated rules for assigning const-qualified pointers which let you make more kinds of assignments without incurring warnings, but still protect against inadvertent attempts to modify const values. C++ would still not allow assigning a char ** to a const char **, but it would let you get away with assigning a char ** to a const char * const *.)
Just since nobody has posted the solution, here:
char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char * const*ps = a; // no error!
(http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17 for why)
The C++11 draft standard explains this in a note in section 4.4 which says:
[ Note: if a program could assign a pointer of type T** to a pointer
of type const T** (that is, if line #1 below were allowed), a program
could inadvertently modify a const object (as it is done on line #2).
For example,
int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; // #1: not allowed
*pcc = &c;
*pc = 'C'; // #2: modifies a const object
}
—end note ]
An interesting related question is Given int **p1 and const int **p2 is p1 == p2 well formed?.
Note the C++ FAQ also has an explanation for this but I like the explanation from the standard better.
The conforming text that goes with the note is as follows:
A conversion can add cv-qualifiers at levels other than the first in
multi-level pointers, subject to the following rules:56
Two pointer types T1 and T2 are similar if there exists a type T and
integer n > 0 such that:
T1 is cv1,0 pointer to cv1,1 pointer to · · · cv1,n−1 pointer to cv1,n
T
and
T2 is cv2,0 pointer to cv2,1 pointer to · · · cv2,n−1 pointer to cv2,n T
where each cvi,j is const, volatile, const volatile, or nothing. The
n-tuple of cv-qualifiers after the first in a pointer type, e.g.,
cv1,1, cv1,2, · · · , cv1,n in the pointer type T1, is called the
cv-qualification signature of the pointer type. An expression of type
T1 can be converted to type T2 if and only if the following conditions
are satisfied:
the pointer types are similar.
for every j > 0, if const is in cv1,j then const is in cv2,j , and similarly for volatile.
if the cv1,j and cv2,j are different, then const is in every cv2,k for 0 < k < j.
There are two rules here to note:
There are no implicit casts between T* and U* if T and U are different types.
You can cast T* to T const * implicitly. ("pointer to T" can be cast to "pointer to const T"). In C++ if T is also pointer then this rule can be applied to it as well (chaining).
So for example:
char** means: pointer to pointer to char.
And const char** means: pointer to pointer to const char.
Since pointer to char and pointer to const char are different types that don't differ only in const-ness, so the cast is not allowed. The correct type to cast to should be const pointer to char.
So to remain const correct, you must add the const keyword starting from the rightmost asterisk.
So char** can be cast to char * const * and can be cast to const char * const * too.
This chaining is C++ only. In C this chaining doesn't work, so in that language you cannot cast more than one levels of pointers const correctly.
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*.