Is const_cast safer than normal cast? - c++

Which is safer to use?
int main()
{
const int i=5;
int *ptr;
ptr=(int*)&i; <------------------- first
ptr=const_cast<int*>(&i); <-------------------Second
return 0;
}

It's safer in the sense that you won't get a cast that's something other than just removing const:
int main()
{
const char i=5;
int *ptr;
ptr=(int*)&i; // the compiler won't complain
ptr=const_cast<int*>(&i); // will fail, since `i` isn't an int
return 0;
}
which doesn't necessary mean that the const_cast<> is safe:
const int i=5;
int main()
{
int const& cri(i);
int& ri = const_cast<int&>(cri); // unsafe
ri = 0; // will likely crash;
return 0;
}

They are entirely equivalent, except that C-style casts present more of a maintenance headache over the const_cast. If the code were frozen in time, they would be identical. The Standard says that the C-style cast may devolve to static, reinterpret, or const cast or a combination of the three, or a strange funky cast that can access private bases for some reason. The point is, in this use case it is exactly equivalent to const_cast.

I'm not sure about safety - I'm sure someone is more well-versed in this than I am - but C++-style casts are part of the language standard and should always be preferred over C-style casts (as a matter of both style as well as readability).
To amend my answer, it appears that C++-style casts are checked by the compiler whereas C-style casts fail at runtime; in that regard, C++-style casts are definitely safer.

Neither is safer than the other. In both cases undefined behavior will occur should you modify the value through one of the pointers that have been casted. const_cast has the benefit of doing only what you want and expresses it clearly, while the C style cast could be everything and is not sensitive to the actual type of its argument.

It's safer, but in a different way than you imagine.
It's safer because you explicitly state you're casting away constness.
When someone sees your code, they think - "ok, here's a const_cast, this argument must have been const. Let's take a closer look at this", whereas a regular cast just gets lost in the back of the mind when reading big chunks of code.

Related

Replace c-style cast (long&) in c++

In a source code, I got this c-style cast :
unsigned long test = 0;
long & truc = (long&)test;
I assume that &truc take the address of test with long type.
How I can do that in C++?
Thanks!
What do you mean by "how [can I] do that in C++"? You've already done it! It works!
Putting aside for a moment the potentially questionable aliasing, a cast to reference type is perfectly valid and does what you expect.
More generally, such a cast might be used to transform an expression into one with the type of its base, without copying the object it describes:
Derived d;
Base& b = (Base&)d;
Although to be idiomatic you'd prefer a static_cast in such a case:
Derived d;
Base& b = static_cast<Base&>(d);
Indeed, the way a C-style cast works in C++ is that, in this particular case (cast to reference of a related type), the C-style cast is a static_cast.
This is also a common pattern with dynamic_cast, which works with a pointer type:
assert(dynamic_cast<T*>(ptr) != nullptr);
but also reference type:
try {
dynamic_cast<T&>(*ptr);
}
catch (const std::bad_cast&) {}
Long story short, there's nothing wrong or weird about a cast to reference type.
That being said, I would avoid questionable conversions like unsigned long to long — it's possible that this aliasing is technically well-defined, but I would have to dive into the standard to be sure, and that in my opinion is reason enough to avoid it.
One upside of switching to static_cast is that, if the conversion is not permitted, you'll be informed. You can then switch in turn to reinterpret_cast and go on with your questionable aliasing. ;)
Addendum
Aliasing between long and unsigned long is allowed ([basic.lval] 10), as long as the value is in range for both. But yeah, best avoided. – Sneftel

About keyword “const” in c++

According to the c++ grammar, const int* const p means that what p points to and it' value can't be rewritten.But today I found that if I code like this:
void f(const int* const p)
{
char* ch = (char*) p;
int* q = (int*) ch;
(*q) = 3; //I can modify the integer that p points to
}
In this condition,the keyword "const" will lose it's effect.Is there any significance to use "const"?
You are casting away the constness here:
char* ch = (char*) p;
Effectively, you are saying "I know what I am doing, forget you are const, I accept the consequences." C++ allows you to do stuff like this because sometimes it can be useful/necessary. But it is fraught with danger.
Note that if the argument passed to the function were really const, then your code would result in undefined behaviour (UB). And you have no way of knowing from inside the function.
Note also that in C++ it is preferable to make your intent clear,
int* pi = const_cast<int*>(p);
This makes it clear that your intention is to cast away the const. It is also easier to search for. The same caveats about danger and UB apply.
Your example will crash the app if const int* const p points to a compile time constant, when casting away constancy you need to be sure what you are doing.
C++ is a language for adults, extra power will never be sacrificed for ephemeral safety, it is the code author's choice whether to stay in a safe zone or to use cast operators and move one step closer to C/asm.
C/C++ will let you do many things that allow you to 'hurt' yourself. Here, casting away the const of p is "legal" because the compiler assumes you know what you are doing. Whether this is good coding style or not is another matter.
When you do something like this, you assume responsibility for any side effects and issues it could create. Here, if the memory pointed to in the parameter is static memory, the program will likely crash.
In short, just because you can do something doesn't mean it is a good idea.
The const keyword is a way to use the compiler to catch programming mistakes, nothing more. It makes no claims about the mutability of memory at runtime, only that the compiler should shout at you if you directly modify the value (without using C-style casts).
A C-style cast is pretty much a marker saying 'I know what I'm doing here'. Which in most instances is false.
Here you change the type of the pointer. Using such a cast (C-type) cast you can change it to any possible pointer with no problem.
The same way you can use c++ cast: const_cast<...>(...):
int* p_non_const = const_cast<int*>(p);
In this case (I hope) you see immediately what is happening - you simply rid of the constness.
Note that in your program you also don't need temprorary variable ch. You can do it directly:
int* q = (int*) p;
In principle you should not use such a cast, because correctly designed and written program doesn't need it. Usually the const_cast is used for quick and temporary changes in the program (to check something) or to use a function from some unproperly designed library.

With or without reinterpret_cast

int main()
{
class_name object;
object.method();
fstream file("writeobject.dat" , ios::out|ios::app);
file.write(reinterpret_cast<char*>(&object), sizeof(object));
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////
int main()
{
class_name object;
object.method();
fstream file("writeobject.dat" , ios::out|ios::app);
file.write((char*)&bk,sizeof(book));
return 0;
}
What is the difference between above both functions. What is reinterpret_cast is doing here? I don't see any of the difference between output of both main() functions.
A C style cast is nothing but the C++ cast that succeeds from the predefined order of:
const_cast
static_cast
static_cast, then const_cast
reinterpret_cast
reinterpret_cast, then const_cast
In this case they are doing the same thing. However, if you are using C++ it is better to use C++ style of explicit casting because they are more indicative of the intent and also it's always better to be explicit about what casting you need than be at the mercy of the compiler to chose one for you.
There is no functional difference between the C-style cast and the reinterpret_cast in the above case.
However the reinterpret_cast might be considered to be preferred by many because it is explicit in what it is doing, both to the compiler and the other humans reading the code.
Being explicit to the compiler is valuable in cases where automatic conversions might take place at times when it is not desired. Consider:
class Foo
{
public:
operator double() const
{
return mD;
}
Foo () : mD (4.12) {};
private:
double mD;
};
int main()
{
Foo foo;
double d = (double) foo;
double d2 = reinterpret_cast <double> (foo);
}
The code:
double d = (double) foo;
compiles, and when it is run the conversion operator operator double() is called. However the reinterpret_cast will not compile because Foo cannot be converted to a double.
To carry the "be explicit" philosophy forward, in cases where you do want the automatic conversion to be available, you can use a static_cast:
double d3 = static_cast <double> (foo);
This will again call the conversion operator.
Aside from the good answers already given, reinterpret_cast is MUCH easier to search for in the code than (char *), which may occur in other places, never mind that a regex type search will need some escaping to not interpret the * as a wildcard.
More importantly, if you want to find EVERY place that you cast something from one pointer type to another, finding all reinterpret_cast is quite easy, where finding all variants of (int *), (char *), (uint8_t *) and (foo **) would be quite a bit of effort to come up with the right regex to match all those without missing something out and not adding some extra finds that you didn't want.
One uses a C++-style reinterpret_cast, the other a C-style cast. The C++ style is better because it's more explicit about what it's doing, and highlights a potentially dangerous operation with verbose syntax.
In this case they do the same as for this combination of target and source type reinterpret_cast is used for the c-style cast. But just a slight change could change that.
Say you had
const class_name object;
and the first form would not compile while the second switched to "reinterpret_cast, then const_cast". And if the function you pass it to actually modified the data, you'd discover that only at runtime.

safety in std::vector memory manipulation

I have this following code
size_t returnSize(const char* s)
{
string string(s);
return string.size();
};
size_t returnSize(const int& i)
{
return sizeof(i);
};
template<typename T>
vector<char> Serialize(const T& t)
{
T* pt = new T(t);
vector<char> CasttoChar;
for (int i =0 ;i<returnSize(t);i++)
{
CasttoChar.push_back(reinterpret_cast<const char*>(pt)[i]);
}
delete pt;
return CasttoChar;
};
template<typename T>
T DeSerialize(const vector<char> cstr)
{
T* a = (T*)(&cstr[0]);
return *a;
}
int _tmain(int argc, _TCHAR* argv[])
{
int x = 97;
vector<char> c = Serialize(x);
cout << DeSerialize<int>(c) << endl;
string k = "blabla";
vector<char> c3 = Serialize(k.c_str());
cout << DeSerialize<const char*>(c3) << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
//output is
//97
//blabla
Is this line T* a = (T*)(&cstr[0]); safe?
Also, I tried reinterpret_cast<T*>(&cstr[0]); instead of T* a = (T*)(&cstr[0]); but compiler complained about not being able to convert const char* to int*. so why does the C style cast work?
Refer the standard
Why reinterpret_cast fails?
5.2.10 Reinterpret cast [expr.reinterpret.cast]
The reinterpret_cast operator shall not cast away constness (5.2.11).
An expression of integral, enumeration, pointer, or pointer-to-member
type can be explicitly converted to its own type; such a cast yields
the value of its operand.
Should I use C Cast?
No. Using C Cast instead of C++ Cast is always unsafe. You are trying to remove the constness of an Object which is an UB.
Using reinterpret_cast, will actually trap this error and advise you of during compile time of the potential pitfall.
You should actually use const_cast in this situation. Its the only legal way to convert a const object to a non const object
But Why does a C Cast works
Quoting from the accepted answer from the Question When should static_cast, dynamic_cast and reinterpret_cast be used?
A C-style cast is defined as the first of the following which
succeeds:
const_cast
static_cast
static_cast, then const_cast
reinterpret_cast
reinterpret_cast, then const_cast
So fortunately, it tries the const_cast first.
The C-style cast works because it takes many steps in order to make the cast succeed. It uses the first of the following that succeeds:
const_cast
static_cast
static_cast + const_cast
reinterpret_cast
reinterpret_cast + const_cast
In this case, it's doing the most 'powerful' cast, a reinterpret_cast to const int * followed by const_cast to int*.
The reinterpret_cast alone won't compile, because you're casting away const-ness. The const_cast is required to cast to int*. Doing a reinterpret_cast to const int* would be fine, however.
As an aside, what you're doing is generally unsafe, unless you're using a compiler extension to ensure that any user-defined type you're deserializing to isn't padded.
C style casting in c++ is not a good idea precisily because you go past the checks that prevent you from removing a const or changing the type arbitrary. If you want to make the code work as is you first need to const_cast and then reinterpret_cast, but really try to avoid const casting. To avoid the warning using reinterpret_cast simply declare a as const T*.
Stick to C++ casts. The reason the reinterpret_cast didn't work is you were casting away constness, which isn't cool; you have to use a const_cast for that and you just shouldn't. C casts ignore this.
Having said that, what are you trying to achieve here? You have effectively casting to a char array and memcpying without the efficiency that would bring.
Sorry to chime in here, but your code is broken in several ways, and the casting is just one of them. Concerning the casting, as soon as you use the conversion from/to vector on something that is not just a simple int or so but requires a constructor it will fail. In any case, a two-step conversions from char const* to void const* to T const* is unfortunately necessary.
Now, other problems:
Try the whole thing with a zero-size string. This should now fully answer your actual question, too: No, it's not safe.
You are returning a pointer to a char from DeSerialize<char const*>(). This pointer points into memory owned by the given vector, which is passed by value and after returning from that function ceases to exist! It is pure luck that it seems to work.
Even if you managed to somehow return a char const* from the function, think about who owns that memory now. The point is that this owner must also release the memory. Consider using std::string and making the char const* variant not compile using a specialization of your template.
In general, if you mean this code earnest, begin adding unit tests. It might slow you down now but avoids errors while you go, thus saving time overall. Search for "test-driven development".
There is nothing that assures that the string is NUL-terminated.
Don't use new/delete unless you have to, prefer "plain" stack variables. If you do, take care of properly releasing the memory in case of exceptions (from push_back()). Use auto_ptr (C++98) or unique_ptr (C++11) to make sure the memory is released correctly.

Why does compiler allow you to "write" a const variable here?

Why can you kind of cheat compiler this way:
const int a = 5;
*((int*)&a)=5; // VC/armcc does not complain
when above is "abridged" equivalent of this:
const int *ptr2const = &a;
int *ptr = ptr2const; // as expected error is raised here
*ptr = 5;
Casting is your way of telling the compiler "I know what I'm doing", so it doesn't complain. Unfortunately, in this instance, you will invoke undefined behaviour.
C-style casts allow you to cast away constness like in your example. In C++, you would normally use the new style casts such as static_cast<>, which don't allow you to cast away constness. Only const_cast<> allows you to do that.
To be equivalent, the 2nd line of the 2nd snippet
int *ptr = ptr2const; // as expected error is raised here
should be written as
int *ptr = (int *)ptr2const;
Because C throws away a lot of type safety in order to gain a lot of speed instead. It cannot prevent you from doing incorrect things. It may try to warn you that you are doing incorrect things, but you can always work around the compiler if that is your goal.
Convert your constant to a string and you may find that while the compiler will let you cast away the const (inadvisable though it may be), the linker may put the constant string in read-only memory leading to a runtime crash.
C-style casts, such as (int*) are equivalent to C++ const_cast in their ability to cast away constness, so you can side-step const-correctness by using them, although such use is unrecommended (can lead to undefined behaviour).
int main()
{
const int x = 1;
(int&)x = 2;
std::cout << x << std::endl;
}
On my system, the above writes 1 to stdout. You might experience different behaviour.
On the other hand...
void foo(const int& x)
{
(int&)x = 2;
}
int main()
{
int x = 1;
foo(x);
std::cout << x << std::endl;
}
This writes 2 for me. The difference is that the const used in foo is const as a type qualifier, while in the main in the first example it was used as a storage class. It's not always easy to see whether a variable was declared with const as a storage class, so it's best not to rely on a const_cast or C-style cast to cast away const.
It's best just to use static_cast in most situations as this will warn you at compile time of any suspect behaviour in the form of a compile error.
This only "works" because the variable is local, and implementations have no way to enforce const-ness on a local (automatic) variable in general (at least not if the address of the variable is ever taken). But as far as the language specification is concerned, this is in the realm of undefined behavior.
If you try this on a global/static variable, you'll quickly find that most implementations can and do enforce const by putting the variable in read-only memory which can be shared between multiple instances of your program.