Is the following code safe :
#include <iostream>
#include <cstdint>
struct A{
int i = 0;
virtual int foo() {return i;}
};
struct B : A{
int foo() override {return i+2;}
};
using handle_t = std::uintptr_t;
handle_t get(B& a){
return reinterpret_cast<handle_t>(&a);
}
void use(handle_t h){
auto p= reinterpret_cast<A*>(h); //
std::cout << p->foo() << "\n";
}
int main(int argc, char *argv[])
{
B a;
auto h = get(a);
use(h);
return 0;
}
CppReference's page says one can :
reinterpret_cast from B* to std::uintptr_t
reinterpret_cast from std::uintptr_t to B* (because it's the same type back and forth)
reinterpret_cast from B* to A*
So, is it safe to merge the last two ?
I don't know what "safe" means, but the behavior of a program that uses this code is undefined. You can convert a pointer into an integer type that's large enough to hold the value, and you can convert that value back into a pointer with the same type as the original. The code in the question doesn't do that: it converts the value into a pointer with a different type from the original.
In that particular case the code is safe. That's because the safety of upcasting. This is always allowed for public inheritance, without an explicit type cast.
In short you're just force something could be consider as implicit.
The passage of B type's address with a uintptr_t is useless also but allowed because "the same type".
Edit
About uintptr_t.
Integer type capable of holding a value converted from a void pointer and then be converted back to that type with a value that compares equal to the original pointer.
Note "compares equal to the original pointer".
Related
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.
Does the C++ standard define a particular behaviour if you make an old C-style cast from type A to type B where type A cannot be cast to type B and vice versa?
Would there be a known visible behavior that can be assumed to be symptom of a illegal cast in runtime using this?
Only one of the four C++-style casts determines the validity of the cast at runtime, namely dynamic_cast.
A C-style cast corresponds to a combination of the other three casts (static_cast, reinterpret_cast, const_cast). The validity of those casts is determined at compile-time, or if it cannot be determined at compile-time then the cast is assumed to be valid. A C-style cast never acts like dynamic_cast.
So a C-style cast that "fails" at runtime, i.e. breaks the validity assumption, causes undefined behavior. So:
Does the C++ standard define a particular behaviour if you make an old C-style cast from type A to type B where type A cannot be cast to type B and vice versa?
No.
Would there be a known visible behavior that can be assumed to be symptom of a illegal cast in runtime using this?
No.
Compiler will catch some of them, but not all. Here is an example of a disastrous cast:
#include <iostream>
#include <string>
using namespace std;
class A {
public:
A(std::string s, int x) : m_s(s), m_x(x) {}
void print() { cout << "A::print(): str = " << m_s << ", x = " << m_x << endl; }
private:
std::string m_s;
int m_x;
};
class B {
public:
B(int x) : m_x(x) {}
void print() { m_x++; cout << "B::print(): x = " << m_x << endl; }
private:
int m_x;
};
int main(int argc, char **argv) {
A *a = new A("abc", 1);
a->print();
B *b = (B*)a;
b->print();
a->print();
return 0;
}
Result on gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609:
A::print(): str = abc, x = 1
B::print(): x = 24828977
A::print(): str = bc, x = 1
Yes, we called B's methods on A's data, which means that our C-style cast worked as reinterpret_cast. reinterpret_cast just takes a memory region and allows you to treat is as something different. No seatbelts here.
On the other hand, if you try to compile something like this
A a;
B b;
a = (A)b;
return 0;
it will result in static_cast and compile-time error. So C-style casting result depends on context.
This is NIGHTMARE when dealing with templates and auto.
To avoid this problem, use static_cast (for compile-time checks) and dynamic_cast (for runtime checks) or reinterpret_cast (for pointers and POD), clearly stating your intent.
Meet a very weird problem, anyone know what is the reason of this? the code is tested under Visual Studio 2012.
#include <iostream>
struct A {
int a;
};
struct B {
int b;
};
struct C : public A, public B {
int c;
};
int main() {
int C::*p = &C::b;
std::printf("%p\n", &C::b); //00000000
std::printf("%p\n", p); //00000004
return 0;
}
Pointers to members are not just plain C-pointers, so passing them to printf is actually undefined behavior, because printf will believe in the "%p" and C-cast the pointer-to-member to void*.
The only conversions of pointers to members allowed by the standard are listed in paragraph 4.11:
Null-pointer constants can be converted to null member pointer values
B::*T can be converted to D::*T if B is an accessible, nonambiguos and nonvirtual baseclass of D.
Pointers to members can actually have different sizes depending on the classes they point into.
See here for more info on pointer-to-member implementations in MSVC: http://blogs.msdn.com/b/oldnewthing/archive/2004/02/09/70002.aspx
Note the possibly unexpected result of:
printf("typeid(&C::b) = %s\n",typeid(&C::b).name());
printf("typeid(&B::b) = %s\n",typeid(&B::b).name());
Which on VS2010 yields:
typeid(&C::b) = int B::*
typeid(&B::b) = int B::*
This indicates that the resulting type for &C::b is a member pointer on type B. Since C is derived from B the pointer is freely convertible to a member pointer on type C. This explains the difference between the two values you see. &C::b is a member function pointer on type B, int C::*p is a member function pointer on type C.
int B::*p_b = &B::b;
int C::*p_c = p_b;
printf("p_b = %p\n", p_b);
printf("p_c = %p\n", p_c);
For static_cast, Is it true that, unless there exist a built-in type conversion function, you cannot use static_cast to perform conversion. But you can do a reinterpret_cast for a type, considering the return type is valid.
int main()
{
WORD word;
HWND hwnd = static_cast<HWND>(word); // error
HWND hwnd = reinterpret_cast<HWND>(word); // ok, considering a valid handle is returned.
}
Do the explicit type conversions done with static_cast require a conversion function unlike reinterpret_cast?
reinterpret_cast just allows you to convert completely unrelated types. It just treats the chunk of memory as another type. So it is very unsafe to use it, since it just doesn't give you any compile or runtime errors but just causes (usually) crash
static_cast provides compile time check of validity of an cast. If an type cannot be treated as another type then static_cast gives you an compile time error when attempting an cast.
It does implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones).
So you can say that it can do the implicit casts for which there is an implicit conversion inbuilt function present. It is usually considered as replacement for c-style casting if that is the confusion.
The C++ casts make most sense when casting pointers and references.
Concrete examples
void foo (Base & b) {
if (b .is_a_Foo ())
static_cast <Foo &> (b) .bar ();
else
b .do_default_bar ();
dynamic_cast <Baz &> (b) .something (); // throws if invalid conversion
}
char data [4];
* reinterpret_cast <float *> (data) = 1.23;
The Windows API is a horrible hack from top to bottom -- in your example, reinterpret_cast is faithful to the original intent (and highlights it for the world to admire) and it basically means "throw away the type system and use the raw bits: trust me".
Basically static_cast allocates memory for compatible class size of destination type and fills it with what is possible, but without any checking that new object is complete. Let me give you an example:
class A {
public:
int a;
};
class B : public A {
public:
int c;
int b;
};
int main()
{
A *a = new A;
a->a = 5;
B *b = new B;
b->a = 6;
b->b = 7;
b->c = 8;
B* bb = static_cast<B*>(a);
A* aa = static_cast<A*>(b);
cout << bb->a << endl; // 5
cout << bb->b << endl; // scrap value from memory
// member b was not initialized, because it was not found in A
cout << aa->a << endl; // 6
return 0;
}
In your example static cast is invalid, because hwnd is void * and word is unsigned short. For c++ casts any type can be considered as a class;
reinterpret_cast works always. It is just a binary copy
I'm having problems getting this to work,
class A {
public:
A(int n) {
a = n;
}
int getA() {
return a;
}
private:
int a;
};
int main(){
A* a[3];
A* b[3];
for (int i = 0; i < 3; ++i) {
a[i] = new A(i + 1);
}
void * pointer = a;
b = (A* [])pointer; // DOESNT WORK Apparently ISO C++ forbids casting to an array type ‘A* []’.
b = static_cast<A*[]>(pointer); // DOESN'T WORK invalid static_cast from type ‘void*’ to type ‘A* []’
return 0;
}
And i can't use generic types for what i need.
Thanks in advance.
Arrays are second-class citizen in C (and thus in C++). For example, you can't assign them. And it's hard to pass them to a function without them degrading to a pointer to their first element.
A pointer to an array's first element can for most purposes be used like the array - except you cannot use it to get the array's size.
When you write
void * pointer = a;
a is implicitly converted to a pointer to its first element, and that is then casted to void*.
From that, you cannot have the array back, but you can get the pointer to the first element:
A* b = static_cast<A*>(pointer);
(Note: casting between pointers to unrelated types requires a reinterpret_cast, except for casts to void* which are implicit and from void* to any other pointer, which can be done using a static_cast.)
Perhaps you mean to do
memcpy(b, (A**)pointer, sizeof b);
?
A static_cast version is also possible.