0

According to this site:

You cannot implicitly assign from a void* to any other type. For instance, the following is perfectly valid in C (in fact, it's arguably the preferable way of doing it in C)

int *x = malloc(sizeof(int) * 10);

but it won't compile in C++.

The explanation from Bjarne Stroustrup himself is that this isn't type safe. What this means is that you can have a void* that points to anything at all, and if you then assign the address stored in that void* to another pointer of a different type, there isn't any warning at all about it.

Consider the following:

int an_int;
void *void_pointer = &an_int;
double *double_ptr = void_pointer;
*double_ptr = 5;
cout<<an_int<<endl;

When you assign *double_ptr the value 5, it's writing 8 bytes of memory, but the integer variable an_int is only 4 bytes. So when you prints the value of an_int variable, output will be 0 because according to 4 bytes compiler select least significant bits of 5(5.000..) that is 0.

In C++, forcing a cast from a void pointer makes the programmer pay attention to these things. So in that language implicitly type conversion from void * is forbidden to give stronger type safety.

but I am literally confused when I'd cast void * to double * in this example like:

int an_int;
void *void_pointer = &an_int;
double *double_ptr = (double *)void_pointer;
*double_ptr = 5;
cout<<an_int<<endl;

The output will remains same that is 0.

So what role type-safety play's here ? and what exactly Bjarne Stroustrup's explained about type-safety ?

Community
  • 1
  • 1
Vikas Verma
  • 3,626
  • 6
  • 27
  • 40

3 Answers3

4

'Type-Safety' means the compiler won't let you use non matching types for operations, unless you're explicitly asking to do so (e.g. doing a c-style, or c++ reinterpret_cast<> type cast, as you're doing in your sample).

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • but in example that I gave type casting plays a nothing role ? so when type casting is useful ? – Vikas Verma Jan 25 '14 at 20:41
  • @VikasVerma: When you have one type (`char`) and you want another (`int`). Or you have a `char*` and you want a `std::string`. – Mooing Duck Jan 25 '14 at 20:43
  • @VikasVerma Type casting from `int*` to `double*` is invalid, since the binary representations of their pointed values are completely different! – πάντα ῥεῖ Jan 25 '14 at 20:43
  • @πάνταῥεῖ type casts are also typesafe, your statement `doing a type cast of ANY kind` is wrong – Sebastian Hoffmann Jan 25 '14 at 20:47
  • Yes: And if you look at the example I give below it tells you that "the compiler won't let you use non matching types for operations..." does not help at all. – Ingo Blackman Jan 26 '14 at 00:42
  • @IngoBlackman _'The point is C++ is not type safe at all.'_ I doubt that seriously! If there are cases you find, **you** are responsible for **breaking** type safety and calling for undefined behavior. Can you elaborate and show more evidence, besides simply showing undefined behavior stuff, using badly type casted raw pointers?? – πάντα ῥεῖ Jan 26 '14 at 00:49
0

Strong static type-safety is a core element of C++. It basically means that you can only transfer information between compatible types, and the most compatible type of any type is that very type. This idea is fortified with ways of using base types with derived type of the same class hierarchy and so on and so forth to great complexity and logical-strength. There is also a core idea that C++ remains as compatible to C as possible. One fall out of this is that void * is compatible with any pointer type. It's usually best avoided, though, as there's always a better design in C++.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
-1

I cannot resist. "Type Safety" is a C++ marketing gag. Consider the following code:

#include <stdio.h>

class A {
public:
    int x;
};

class B : public A {
  // B is derived from A, which makes
  // B "compatible" to A
public:
  // B adds a 2nd member, which means
  // that B is "bigger" than A
    int y;
};

int main()
{
    B a1[10];
    A *a2;
    a2 = a1; // this is legal :-( 
    a1[0].x=1;
    a1[0].y=1;
    a2[0].x=2;
    a2[1].x=3; // Upps: this probably overwrites a1[0].y
    printf("a1[0].x = %d\n",a1[0].x);
    printf("a1[0].y = %d\n",a1[0].y);
    return 0;
}

Compile this with "g++ -Wall -pedantic -fstrict-aliasing" or whatever other options you find. I at least have not managed to produce a warning. The code above does not use any type casts and still you get code which breaks or at least quite certainly does not do what you think it should do.

A C++ guru might now recommend to use "vector" or whatever else. But that's not the point. The point is C++ is not type safe at all.

EDIT: Since this seems to be confusing, here is an explanation of what the source of the problem is.

Because C++ is object oriented "class B" is compatible to "class A" (because "class B" is derived from "class A"). So that means you might use a "class B" object at a place where a "class A" object is required. This in turn means you might use a "class B *" pointer at a place where a "class A *" pointer is required.

Now the problem is that C++ allows pointer arithmetic (because of it's C legacy). Pointer arithmetic interacts rather badly with inheritance and compatible types. Because in the example above "a2+1" (a2 is a "class A *" pointer) results in a different address than "a1+1" (a1 is a "class B *" pointer).

So to summarize: C++ deems type "class B *" to be compatible to type "class A *" but unfortunately these types are not compatible when you use them for pointer arithmetic.

Ingo Blackman
  • 991
  • 8
  • 13
  • That's all plain wrong! @IngoBlackman _'The point is C++ is not type safe at all.'_ I doubt that seriously! If there are cases you find, **you** are responsible for **breaking** type safety and calling for undefined behavior. Can you elaborate and show more evidence, besides simply showing undefined behavior stuff, using badly type casted raw pointers?? – πάντα ῥεῖ Jan 26 '14 at 00:50
  • And BTW, decent compilers **are** able to detect mismatching `printf()` formatting specifiers against the parameter types you're passing and give you at least a warning for that! – πάντα ῥεῖ Jan 26 '14 at 01:00
  • The problem you're mentioning here is probably [slicing](http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c), but that's still in scope of being handled correctly by the user, the compiler can't know that you're misusing c++ like this. – πάντα ῥεῖ Jan 26 '14 at 01:05
  • Can you tell me in the example above, where there are "badly type casted raw pointers" ? There is NO type cast. Why do you mention "printf" ? That is just for outputting the values. The problem is the line ABOVE the printfs. – Ingo Blackman Jan 26 '14 at 01:06
  • @πάντα ῥεῖ : Yes the problem I am referring to is also known as "slicing". "the compiler can't know that you're misusing c++ like this". So the compiler can't know ? I thought it is a "TYPE SAFE" language. So WHY can't the compiler know ? (No type casts no nothing so why ?) – Ingo Blackman Jan 26 '14 at 01:09
  • @πάντα ῥεῖ : So if you noticed it's about slicing, why did you mention "printf" ? – Ingo Blackman Jan 26 '14 at 01:10
  • 'Type safety' means you can't do that, without expecting undefined behavior! – πάντα ῥεῖ Jan 26 '14 at 01:11
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/46095/discussion-between-ingo-blackman-and--) – Ingo Blackman Jan 26 '14 at 01:12
  • _'So if you noticed it's about slicing, why did you mention "printf"'_ Took some time OK? – πάντα ῥεῖ Jan 26 '14 at 01:12
  • **To summarize (from chat):** Copies aren't referring to the same instances as their originals in [tag:c++] as they are likely to be handled in [tag:Java] or [tag:c#]. That doesn't invalidate [tag:c+] being a 'Type-Safe' language! – πάντα ῥεῖ Jan 26 '14 at 01:50
  • I agree that this is one of many gotchas in C++ that make it a dangerous language to use. However, the rules are: (1) You can take the address of the first element of an array of `A` and do pointer arithmetic on that pointer to get subsequent elements of that array, (2) you can convert a pointer to `B` to a pointer to `A`. That's **all** you can do legally; you cannot legally do what you are doing, which is doing pointer arithmetic on a pointer to `A` that points into an array of `B`s. This is simply not a legal thing to do in C++ and you are required to know that and not do this. – Eric Lippert Jan 27 '14 at 16:49
  • @eric: how do you define "legal" ? the compiler is not even able to produce a warning. I think a language which allows such a construct is simply bad language design and **certainly** not "type safe". – Ingo Blackman Jan 28 '14 at 00:32