I had to change the prototype of a function getData() which is basically a legacy source code. Upon changing it from returning a char* as shown below, I started getting compile errors due to static_cast.The question I have is , Is it safe to use reinterpret_cast, instead of static_cast?
class C1{
public:
//void *getData() {return data;} //Legacy implementation*
char *getData() {return data;} //My new implementation
private:
char data[100];
};
int main()
{
C1 myobj;
unsigned char* begin;
begin=static_cast<unsigned char*>(myobj.getData()); *//<== This gives compile error.use reinterpret_cast ?*
return 0;
}
Is there a better solution than reinterpret_cast ?
You can static_cast from a void * to any pointer type, or between pointers to related types in the sense when one herites from the other.
reinterpret_cast is intended to be used between pointers to unrelated types. Is is equivalent to a static_cast from first type to void * followed with a static_cast from void * to second type. It T and U are unrelated types:
U *u = ...;
T *t;
t = reinterpret_cast<T *>(u); /* strictly the same as would be
t = static_cast<T *>(static_cast<void *>(u)); */
It depends of what you want to accomplish. If you want to just use the bitwise representation of data, with each element interpreted as unsigned char, then reinterpret_cast is the way to go.
Your question doesn't give us enough details to figure out if it is "safe" in your case.
Related
I am writing a code in C++ right now, and I have a dilemma.
EDIT: I added the class relevant definition
_fullName is defined in the class as a private dm(char _fullName)
my class contains the getter method below:
char* getFullName() const { return this->_fullName; }
However, I had in the past cases in which I returned char* with const(const char*)
I can change the getter method to this one:
const char* getFullName() const { return this->_fullName; }
Both versions are compiling but I don't know how to choose.
I would take the second version, but I wonder Why even the version without the const is compiling? shouldn't it give an error when I remove the const keyword, because the function is a CONST member function and therefore the dms are const as well and cannot be returned without the const keyword???
This is the class relevant definition:
class Professional
{
private:
char* _ID;
char* _fullName;
int _age;
char* _profession;
}
First understand what const attached to a member function means. It determines the const-ness of the implicit this used for the member. Given this:
struct S
{
char value[10];
const char *mfn() const { return value; }
};
within the confines of mfn the implicit this is const S *. Furthermore, all references to members obtained therein are also const. In this case, that means value as an expression representation is const char (&)[10] before any further conversion are attached therein.
That's important.
In the correct posted example above there is an automatic conversion to temporary pointer, since const char(&)[10] converts to const char* without objection. However, the following will fail:
struct S
{
char value[10];
char *mfn() const { return value; }
};
The reason this will fail is simply because there is no conversion possible. value, remember, is const char (&)[10], and can only implicitly convert to const char*.
But how could it succeed? Well, consider this:
struct S
{
char *ptr;
char *mfn() const { return ptr; }
};
This will work. The reason is subtle, but obvious once you think about it. ptr is a char*. The attachment of const to this makes that char * const&, not const char *& (there is a difference; the former is a reference to a non-mutable pointer to mutable data, the latter is a reference to a mutable pointer to non-mutable data). Since return ptr is not mutating ptr (or anything else in the object), it is viable as a result.
In short, in your case it works because the pointer you are returning isn't via some implicit conversion from a const underlayment; it's just a value.
You have a few things going on here, in your example of the int num member this is not the same as a char * member.
lets expand your example a bit:
class Professional
{
int* func() const
{
return &myInt; // Fails because it returns a reference to a member variable
}
char* func() const
{
return &myChar; // Fails because it returns a reference to a member variable
}
int* func() const
{
return pInt; // ok because it returns a COPY of the member pointer
}
char* func() const
{
return pChar; // ok because it returns a COPY of the member pointer
}
int myInt;
char myChar;
int *pInt;
char *pChar;
Note: the two pointers getting returned by copy are ok. Its the pointers that are copies not the thing being pointed to. The memory that is pointed to is nothing to do with this class.
As to an answer to your question: there is a rule of thumb that is to apply const as much as possible - this helps to show other users your intent and gains benefits from compiler warnings / errors if a user tries to use your class in a way you did not intend. So in this case pass back a const char *.
Note: See this answer for more specific details here: What is the difference between const int*, const int * const, and int const *?
Comments are sprinkled throughout boost::asio that say this:
The boost::asio::buffer_cast function permits violations of type
safety, so uses of it in application code should be carefully
considered.
However, ultimately what the buffer interface boils down to is this:
struct buffer {
void *data;
friend void* cast_helper(const buffer& b);
};
void* cast_helper(const buffer& b) {
return b.data;
}
template <typename to_t>
to_t buffer_cast(const buffer& b) {
return static_cast<to_t>(cast_helper(b));
}
static_cast a void* to a pointer type is well-defined and considered the appropriate thing to do for void* data (see "Should I use static_cast or reinterpret_cast when casting a void* to whatever"). So what does it mean by violating type-safety?
Consider the following code:
char i = 2;
buffer b;
b.data = &i;
double *pd = buffer_cast<double*>(b);
*pd = 1.0;
This will compile correctly, but it obviously invokes undefined behaviour. It's no different really to:
char i = 2;
void *pv = &i;
double *pd = static_cast<double*>(pv);
*pd = 1.0;
In both the case of static_cast and buffer_cast a reviewer needs to look carefully at the code to make sure the cast is legal.
Using static_cast to convert a void* to a pointer type is only well defined if the void* was originally obtained from a pointer of that type or something similar (where "similar" includes some, but not all, base/derived relationships, and unsigned char vs plain char vs signed char, etc).
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*.
Ignoring how repulsive and hacky it is, is the following guaranteed to be safe? If not, why?
//.h
struct foo
{
const static intptr_t KEY = (intptr_t) "VALUE";
};
//.cpp
void useFoo()
{
const char * value = (const char *) foo::KEY;
printf("%s",value);
}
Not only is the code not guaranteed to be safe, the code is ill-formed.
"VALUE" is of type char const[6], which cannot be converted to intptr_t via static_cast.
It is guaranteed not to compile. You cannot use static_cast to convert from pointer to an integral type or viceversa. If it was a reinterpret_cast it would be fragile to say the least as the compiler can do constant folding and the KEY might become non-unique.
Additionally, you should define the static member variable KEY in your application.
I have a problem understanding why a certain implicit conversion is not working as I expect it. I have the following class
ref class ManagedWStringArrayWrapper
{
wchar_t** m_pointer;
public:
operator wchar_t**()
{
return m_pointer;
}
};
and I thought this would implicitly convert to const wchar_t ** as well - but it doesn't. Can someone tell me why?
Conversion from T** to T const** is not as intuitive as you might expect — in fact, it's given as an example in the standard itself as const-incorrect code.
The example given is:
#include <cassert>
int main() {
char* p = 0;
//char const** a = &p; // not allowed, but let's pretend it is
char const** a = (char const**)&p; // instead force the cast to compile
char const* orig = "original";
*a = orig; // type of *a is char const*, which is the type of orig, this is allowed
assert(p == orig); // oops! char* points to a char const*
}
Study the above scenario for a while and it will become clear that this is not the same as a conversion T* → T const*. Not at all!
I asked the same question in a blog post, and the FAQ has an entry on it too.
Because those are different things. If you look, for instance, at the C++ libraries, you'll find that there are often two functions for doing the same thing, one operating on const pointers and the other on non-const. Example.
But you can easily add an explicit operator const wchar_t**.