This question already has answers here:
How to convert "pointer to pointer type" to const?
(2 answers)
Closed 9 years ago.
I have the very simple code in c++. When I compile under Visual studio, the error happens.
#include <stdint.h>
#include <time.h>
void func1(const uint8_t* data)
{
}
void func2(const uint8_t** data)
{
}
int main()
{
uint8_t* data1 = NULL;
uint8_t** data2 = NULL;
func1(data1);//OK
func2(data2);//error C2664: cannot convert argument 1 from 'uint8_t **' to 'const uint8_t **'
}
the full error meesage is:
error C2664: 'void func2(const uint8_t **)' : cannot convert argument 1 from 'uint8_t **' to 'const uint8_t **'
Usualy you cannot convert const XXX to XXX, but from XXX to const XXX should be OK, Why this error happens here?
but from XXX to const XXX should be OK
No, this isn't okay in this specific instance. Consider:
int const x = 10; // implementation stores to read-only memory
// implementation crashes on writes to read-only memory
void foo(int const **ptr) {
*ptr = &x;
}
int main() {
int *p;
foo(&p);
*p = 12; // crash
}
If this were legal it would assign a 'pointer to const' value to a 'pointer to non-const' object, and therefore enable dangerous writing to constant objects.
For a conversion to const to be okay const must be added at every level in the type above where the lowest const is added (except the very top).
For example it's not okay to convert int ****** to int ***const***, but it is okay to convert it to int ***const*const*const*. This also applies to volatile: you can convert int ****** to int ***volatile*const*const* but not int ***volatile***
This rule in the type system protects us from mistakenly treating const objects as non-const, or volatile objects as non-volatile, and if we really want to make this mistake then we have to use const_cast.
foo(const_cast<int const **>(&p));
*p = 12; // crash
With const cast the program is well formed and the compiler happily produces an executable that exhibits undefined behavior. (live example)
Fixing foo() to allow it to take a pointer to non-const:
void foo(int const * const *ptr) {
*ptr = &x; // error, can't modify *ptr
}
foo(&p); // conversion works fine
prevents foo() from writing a 'pointer to const' value into a 'pointer to non-const' object. (live example)
You probably got the idea that XXX to const XXX is okay because the most common case of this, i.e. with single level pointers: int * -> int const *, is okay and also obeys the above conversion rule. const at the very top level doesn't matter because changes to the parameter itself won't escape the function.
When you use const to pointer of pointer you need to use uint8_t const* const*
#include <stdint.h>
#include <time.h>
void func1(const uint8_t* data) {
}
void func2( uint8_t const* const* data ) {
}
int main() {
uint8_t* data1 = NULL;
uint8_t** data2 = NULL;
func1(data1);//OK
func2(data2);
}
Here are your two options, this...
void func1(const uint8_t* data)
{
}
void func2(const uint8_t** data)
{
}
int main()
{
const uint8_t* data1 = NULL;
const uint8_t** data2 = NULL;
func1(data1);
func2(data2);
}
Or this...
void func1(uint8_t* data)
{
}
void func2(uint8_t** data)
{
}
int main()
{
uint8_t* data1 = NULL;
uint8_t** data2 = NULL;
func1(data1);
func2(data2);
}
Related
Is there any way I could write the two lines (7 and 8) of code into one line? I think I understand why the error occurs.
int value = 5;
int &GetValue() { return value; }
int main() {
const int *my_value = (const int *)&(GetValue()); // 7
const int *const *my_value_pp = (const int *const *)&(my_value); // 8
// This gives error for saying cannot take the address of an rvalue of type 'int *'
// const int* const * my_second_value_pp = (const int* const*)(&(&(Getvalue()));
}
I need this since there is a function (which I did not write) that takes a const int *const * as an argument.
First, the two lines does not require casting, so just write:
const int* my_value = &GetValue(); // 7
const int* const* my_value_pp = &my_value; // 8
You can however not write that as a one-liner as the function you are going to call needs the address of my_value. You can however skip my_value_pp and call your function using my_value directly:
void func(const int* const*) {} // example function taking a const int* const*
func(&my_value); // &my_value is a const int**
I have these two cpp file.
When I try to coding a template function Method(), the C2440 error occurs.
I tried three different way to do the assignment. Only the C-style cast can pass the compiler.
I want to know how to do that in C++-style.
Thanks : )
FileA:
template <typename T>
int ClassName<T>::Method(params...)
{
const T* temp = (T*)GetValueArray(); // C-style cast, right √
const T* temp = GetValueArray(); // no cast, error C2440
const T* temp = static_cast<T*>(GetValueArray()); // error C2440, reinterpret or
// const or dynamic_cast all C2440
}
_______________
FileB:
typedef double mytype;
const mynamespace::mytype* GetValueArray() const
{
mynamespace::mytype res[3] = {1,2,3};
return res;
}
#include <iostream>
typedef double MyType;
const MyType* GetValueArray()
{
MyType* ptr = new MyType;
*ptr = 20.20;
return ptr;
}
template <typename T>
void Method()
{
const T* temp = (T*)GetValueArray(); // C-style cast, right √
//const T* temp = GetValueArray(); // no cast, error C2440
//const T* temp = static_cast<T*>(GetValueArray()); // error C2440, reinterpret or
// const or dynamic_cast all C2440
std::cout << *temp;
}
int main(int argc, char* argv[])
{
Method<double>();
}
I get the output 20.2. Here I can get the right result, because T is just double. In this situation, with lost const, the program can pass the compiler.
But if I change to Method<int>, no matter what the result is (actually the result is useless number), but why C2440 will occur?
Your cast lost the const-ness
const T* temp = static_cast<const T*>(GetValueArray());
The reason the C-style cast works is the one of the casts it tries is a const_cast which is likely not what you want in this case.
I do not understand why line 21 is ok but line 25 is error?
The error message:
invalid conversion from 'const int*' to 'int*' [-fpermissive]
Push is function in class that decleared like this:
template< typename Type >
class Stack {
void Push(const Type& value) {
SNode* type = new SNode();
if (this->head != nullptr) {
this->head->up = temp;
}
temp->value = value;
temp->up = nullptr;
temp->down = head;
temp->head = temp;
num_of_elements++;
}
};
int main() {
Stack<int*>* stk = new Stack<int*>();
int a = 5;
int* x = &a;
stk->Push(x); //this line is fine
const int b = 5;
const int* y = &b;
stk->Push(y); //this line is an error
delete stk;
return 0;
}
It's look like function Push get parameter from type of "const int * &" , and in line 25 , i exactly sends a const pointer "const int *". so what is the problem?
The Push() in line 21
int a = 5;
int * x = &a;
stk->Push(x);
where Push() wait for a const Type & value (with Type equal to int *, if I understand correctly), works because you're sending a int * to a method that is wainting for a compatible type, a const Type & that is int * const &.
Remember that const is applied on the left, on the right when there isn't nothing on the left, so const Type & is Type const & that is int * const &. So is a reference to a constant pointer to a not-constant integer.
When you write (Push() in line 25)
const int b = 5;
const int * y = &b;
stk->Push(y);
you're sending a const int *, that is a int const * (not-constant pointer to a constant integer), to a method that is waiting for a int * const & (a reference to a constant pointer to a not-constant integer).
The two types are incompatibles, so the error.
You can try with
int b = 5;
int * const y = &b;
stk->Push(y);
This should work.
First off I would like to mention that this works with MSVC but not with clang. I am using Clang with c++11.
I have a function pointer:
typedef void (*Log) (const char* title, const char* msg, const char* file, int line);
I have this struct:
struct FunctionList
{
protected:
static const int kNbrMax = 32;
FunctionList();
bool Add(const void* f);
bool Remove(const void* f);
const void* m_functions[kNbrMax];
};
And this class:
template<typename T>
struct MessageFunctionList
: public FunctionList
{
public:
MessageFunctionList(T defaultFunction)
{
Add(defaultFunction);
}
void Call(const char* title,const char* cause,const char* file,int line)
{
for (unsigned long i = 0;i < m_nbrUsed;++i)
{
reinterpret_cast<T>(m_functions[i])(title,cause,file,line);
}
}
}
I am creating it like so:
static void DefaultLogMessageFunction(const char* title,const char* msg,const char* file,int line)
{
}
MessageFunctionList<Log> functionList(DefaultLogMessageFunction)
But I get the compile time error:
reinterpret_cast from 'const void ' to 'void ()(const char *, const
char *, const char *, int)' casts away qualifiers for line:
reinterpret_cast(m_functions[i])(title,cause,file,line);
So as far as I understand I am trying to cast my const list of functions to a non const value. That is not allowed which makes sense. So I tried the following:
const void* funcPtr = m_functions[i];
const T call = reinterpret_cast<const T>(funcPtr);
call(title, cause, file, line);
But that does not work either.
This works:
void* funcPtr = const_cast<void*>(m_functions[i]);
T call = reinterpret_cast<T>(funcPtr);
call(title,cause,file,line);
But I would like to avoid using a const cast. What am I doing wrong? How can I call this const function? Or is it simply not allowed because it does not know if the function being called is a const function or not? Or perhaps it is because my static function is not a member of a class so it can not be declared const?
You are storing the function pointers as const void*:
const void* m_functions[kNbrMax];
And you are trying to cast them to T and call it using reinterpret_cast:
reinterpret_cast<T>(m_functions[i])(title,cause,file,line);
However, reinterpret_cast cannot remove const qualifier from a type, therefore, you should first remove the const using const_cast:
reinterpret_cast<T>(const_cast<void*>(m_functions[i]))(title,cause,file,line);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
However, please note that const_cast engenders undefined behavior and is unsafe. So is calling a function pointer returned from reinterpret_cast if the original pointer was not actually a T.
Edit:
You can call a const qualified function pointer, however, then the reinterpret_cast should contain the const qualifier:
reinterpret_cast<const T>(m_functions[i])(title,cause,file,line);
is possible to re-map STL class object from void* ?
#include <string>
void func(void *d)
{
std::string &s = reinterpret_cast<std::string&>(d);
}
int main()
{
std::string s = "Hi";
func(reinterpret_cast<void*>(&s));
}
Use static_cast to convert void pointers back to other pointers, just be sure to convert back to the exact same type used originally. No cast is necessary to convert to a void pointer.
This works for any pointer type, including pointers to types from the stdlib. (Technically any pointer to object type, but this is what is meant by "pointers"; other types of pointers, such as pointers to data members, require qualification.)
void func(void *d) {
std::string &s = *static_cast<std::string*>(d);
// It is more common to make s a pointer too, but I kept the reference
// that you have.
}
int main() {
std::string s = "Hi";
func(&s);
return 0;
}
I re-wrote as following,
#include<string>
void func(void *d)
{
std::string *x = static_cast<std::string*>(d);
/* since, d is pointer to address, it should be casted back to pointer
Note: no reinterpretation is required when casting from void* */
}
int main()
{
std::string s = "Hi";
func(&s); //implicit converssion, no cast required
}
You code shouldn't compile.
Change
std::string &s = reinterpret_cast<std::string&>(d);
to
std::string *s = static_cast<std::string*>(d);
EDIT:
Updated code. Use static_cast instead of reinterpret_cast
Yes, it is possible, but you are trying to cast from a pointer to void *, then to a reference. The reinterpret_cast operator only allows casting back to exactly the same type that you started with. Try this instead:
void func(void *d)
{
std::string &s = *reinterpret_cast<std::string*>(d);
}