The following code compile well both with GCC (4.2-4.6) and with Clang (2.1), but when I run the executable it gives me "Bus error: 10". I don't understand the reason.
#include <iostream>
struct A
{
static int const v;
A() { ++*const_cast<int *>(&A::v); }
};
int const A::v = 0;
int main(int argc, char * argv[])
{
A a, b, c;
std::cout << a.v << std::endl;
return 0;
}
I think the relevant quote is:
§ 7.1.6.1 (4) from N3242:
Except that any class member declared mutable can be modified, any
attempt to modify a const object during its lifetime results in
undefined behavior.
The examples illustrate the point using const_cast. As James pointed out: the quote can be found in §7.1.5 in the C++03 standard.
A little elaboration: That language rule allows the compiler to use read-only memory (if it is available on the target architecture) when something is declared const. Without this rule const-ness could always be casted away without fearing any consequences and using it would only be a matter of developer discipline. The way it is you can at least tell people that they are invoking UB, which usually is a good deterrent. The const_cast itself is of minor relevance as it does not matter how you trick the compiler in letting you manipulate a const object.
5.2.11.7:
Depending on the type of the object, a write operation through the
pointer, lvalue or pointer to data member resulting from a const_cast
that casts away a const-qualifier) may produce undefined behavior
(7.1.5.1)
In your case, you are trying to modify data that is in read-only segment.
Because you're not allowed to modify variables declared as const.
Just because you've cast away const, doesn't mean that you will succeed in writing to that memory.
All that const_cast<T> does is remove the const-ness of the variable from the compiler's perspective. That lets the compiler go ahead and emit code to write to the variable. But at runtime, if the compiler/linker happened to put the variable in read-only memory, then the hardware will stop you writing there no matter how you cast it.
I don't have a solution for the actual problem. I just can say, don't use const_cast unless the intention is to call a const member function from a non-const member function and "const_cast" the const result (to make it a mutable result for the non-const member function).
But I have a proposal for improving your design:
class A
{
private:
static int v;
public:
A() { ++v; }
static int get_v() { return v; }
};
int A::v = 0;
int main(int argc, char * argv[])
{
A a, b, c;
std::cout << a.get_v() << std::endl;
return 0;
}
Basically, if a variable is declared const, the compiler is allowed to emit the results to read only memory. Taking a pointer/reference to a const object and then using const_cast to remove the const can result in undefined behavior.
In general, it is only safe to use const_cast if the object being refered to is non-const (even if the pointer/reference you have is const).
The problem is this line :
static int const v;
Because you declared it const, the const_cast is causing an undefined behaviour - in your case you are lucky with getting bus error (it is a segmentation fault on my system).
Declare it non-const, and you can call const_cast on it without problems.
Related
as we all know the usage of const_cast to remove the const-ness of a pointer should be avoided.
But how is it about the other way around?
For my use case I have a function that copies data (bytes) from a non-const source buffer.
I thought a good design decision would be to declare the parameter according to that source buffer fully const.
void copyfunction(const char* const data) { ... }
For a function call like below this would lead to a pointer-type error 'const char* const <-> char*'.
void main() {
char sourcebuffer[] = {0x00};
copyfunction(sourcebuffer);
}
Sure, now I could simply declare the sourcebuffer as const but in my case I don't have access to that variable because it's from a different code location (external library).
void main() {
char sourcebuffer[] = {0x00};
copyfunction(const_cast<const char* const>(sourcebuffer));
}
However the code beyond would work but is it good style (according to my use case)?
I thought declaring the parameter of the copyfunction as const assures the user of not modifying (read-only) the pointer or the location of the source buffer itself.
So in this case the const_cast would only be a necessary evil to enable to function call and not willfully remove the const-ness of a pointer...
Greets
You should not use const_cast to add const, because:
it's unnecessary. T* converts implicitly to const T*. Your question states that char sourcebuffer[] = {0x00}; copyfunction(sourcebuffer); is an error, but that's not true.
it's potentially (albeit unlikely) harmful. It can remove volatile from the pointer type, which is not the intention here and would result in undefined behavior if sourcebuffer were declared as volatile sourcebuffer[].
You should not use const_cast to add const because
In the cases where the operation is safe, it is almost always not required. int* turns into a const int* implicitly.
It can do something you don't want it to do. It can strip volatile, or make you miss the fact that const was added somewhere else in your variables and your const_cast now silently strips them.
In the cases where it is required to add const, its use is dangerous in hard to reason about ways.
There are cases where you need to call const_cast in order to add const that will not happen implicitly.
void assign_ptr( int const*& lhs, int const* rhs ) { lhs = rhs; }
int const foo = 7;
int* bar = nullptr;
assign_ptr( const_cast<int const*&>(bar), &foo );
*bar = 2; // undefined behavior!
std::cout << foo << "#" << &foo << "\n"; // will print probably 7#something
std::cout << *bar << "#" << bar << "\n"; // will print probably 2#same address as above!
the above call to assign_ptr only adds const, but it will not happen implicitly.
A side effect of it is that modification of *bar is undefined behavior, as it modifies a variable declared const (it makes bar, a int*, point at foo a const int).
So while const_cast is required to make the assign_ptr call compile, it is because it was unsafe. The const_cast doesn't make it safer, it just hides the error.
This is a specific case of the rectangle-square problem. Squares are not Rectangles, because if you change the width of a Square its height also changes, and this does not happen when you modify a Rectangle. Similarly, int** are not int const**. (Note that immutable Squares are a kind of immutable Rectangle; it is the mutation that causes the issue. In the case of pointers, a int*const* is a int const*const*: the mutability of the "higher level" pointers causes the problem.)
In a response to my comment to some answer in another question somebody suggests that something like
void C::f() const
{
const_cast<C *>( this )->m_x = 1;
}
invokes undefined behaviour since a const object is modified. Is this true? If it isn't, please quote the C++ standard (please mention which standard you quote from) which permits this.
For what it's worth, I've always used this approach to avoid making a member variable mutable if just one or two methods need to write to it (since using mutable makes it writeable to all methods).
It is undefined behavior to (attempt to) modify a const object (7.1.6.1/4 in C++11).
So the important question is, what is a const object, and is m_x one? If it is, then you have UB. If it is not, then there's nothing here to indicate that it would be UB -- of course it might be UB for some other reason not indicated here (for example, a data race).
If the function f is called on a const instance of the class C, then m_x is a const object, and hence behavior is undefined (7.1.6.1/5):
const C c;
c.f(); // UB
If the function f is called on a non-const instance of the class C, then m_x is not a const object, and hence behavior is defined as far as we know:
C c;
const C *ptr = &c;
c->f(); // OK
So, if you write this function then you are at the mercy of your user not to create a const instance of C and call the function on it. Perhaps instances of C are created only by some factory, in which case you would be able to prevent that.
If you want a data member to be modifiable even if the complete object is const, then you should mark it mutable. That's what mutable is for, and it gives you defined behavior even if f is called on a const instance of C.
As of C++11, const member functions and operations on mutable data members should be thread-safe. Otherwise you violate guarantees provided by standard library, when your type is used with standard library functions and containers.
So in C++11 you would need to either make m_x an atomic type, or else synchronize the modification some other way, or as a last resort document that even though it is marked const, the function f is not thread-safe. If you don't do any of those things, then again you create an opportunity for a user to write code that they reasonably believe ought to work but that actually has UB.
There are two rules:
You cannot modify a const object.
You cannot modify an object through a const pointer or reference.
You break neither rule if the underlying object is not const. There is a common misunderstanding that the presence of a const pointer or const reference to an object somehow stops that object from changing or being changed. That is simply a misunderstanding. For example:
#include <iostream>
using namespace std;
// 'const' means *you* can't change the value through that reference
// It does not mean the value cannot change
void f(const int& x, int* y)
{
cout << "x = " << x << endl;
*y = 5;
cout << "x = " << x << endl;
}
int main()
{
int x = 10;
f(x, &x);
}
Notice no casts, nothing funny. Yet an object that a function has a const reference to is modified by that function. That is allowed. Your code is the same, it just does it by casting away constness.
However, if the underlying object is const, this is illegal. For example, this code segfaults on my machine:
#include <iostream>
using namespace std;
const int i = 5;
void cast(const int *j)
{
*const_cast<int *>(j) = 1;
}
int main(void)
{
cout << "i = " << i << endl;
cast(&i);
cout << "i = " << i << endl;
}
See section 3.4.3 (CV qualifiers) and 5.2.7 (casting away constness).
Without searching any further, § 1.9/4 in the C++11 Standard reads:
Certain other operations are described in this International Standard
as undefined (for example, the effect of attempting to modify a const
object).
And this is what you are trying to do here. It does not matter that you are casting away constness (if you didn't do it, the behaviour is well defined: your code would fail to compile). You are attempting to modify a const object, so you are running into undefined behaviour.
Your code will appear to work in many cases. But it won't if the object you are calling it on is really const and the runtime decided to store it in read-only memory. Casting away constness is dangerous unless you are really sure that this object was not const originally.
Is the code below bad practice or undefined behavior? Essentially i am calling a const func to modify a member which is not marked as mutable. Link to demo
Credits to Mehrdad for inspiring this question (his question Does this code subvert the C++ type system?) and david for minor demo improvements.
#include <iostream>
using namespace std;
struct BreakConst
{
int v;
int *p;
BreakConst() { v = 0; p = &v; }
void break_stuff() const { ++*p; }
};
void f(const BreakConst& bc) {
bc.break_stuff();
}
Original Version that most answers are based on:
Answered by David Rodríguez, jpalecek, Mehrdad
Yes: This is "Undefined behavior"
int main()
{
const BreakConst bc;
cout << bc.v << endl; // 0
bc.break_stuff(); // O:)
cout << bc.v << endl; // 1
return 0;
}
New Alternative Question:
Answered by Mehrdad
No: This is not "Undefined behavior"
int main()
{
BreakConst bc;
cout << bc.v << endl; // 0
f(bc); // O:)
cout << bc.v << endl; // 1
return 0;
}
Result:
0
1
In this case, I'd say it's undefined behaviour. bc is a const object, so are all its subobjects (less mutables)1, therefore bc.v should be, too and modifying a const object, however achieved, is UB2.
[1] C++03 3.9.3/3:
Each non-static, non-mutable, non-reference data member of a const-qualified class object is const-
qualified...
[2] C++03 7.1.5.1/4:
Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const
object during its lifetime (3.8) results in undefined behavior.
EDIT responding to the edit of the question: No, the modified version of the code does not cause undefined behavior. It may be bad practice, but actually may be useful at times. You can eg. use it to implement iterators to your classes via const-iterators (DRY):
class const_iterator
{
public:
const T& dereference() const; // complicated
};
class iterator : public const_iterator
{
public:
T& dereference() const { return const_cast<T&>(const_iterator::dereference()); }
};
Of course that relies on the fact that iterators can only be made from mutable containers, that the const and non-const versions do not differ (no COW and such) etc., but that is fairly common.
In your particular case it is undefined behavior as the object is const, not just the reference. It would be bad practice (and dangerously close to Undefined Behavior) in the following case:
void f( const BreakConst& b ) {
bc.break_stuff();
}
int main() {
BreakConst b;
f( b );
}
The difference is that in this case the actual object is not const, even if the reference at the level of f is. The dangerously close to Undefined Behavior comes from the fact that the member function casting away const-ness cannot possibly know whether the object on which it has been called is const or not, so you have lost all control.
After your edit:
No, it's not undefined. You're allowed to modify a mutable object through a const reference; it's completely allowed and legal.
Before your edit:
Yes, it must be undefined, because the standard (I'm looking at the draft here) clearly says:
§7.1.6.1.4
Except that any class member declared mutable (§77.1.1) can be modified, any attempt to modify a const object during its lifetime (§3.8) results in undefined behavior.
So yes -- since the member isn't mutable, modifying it is obviously undefined behavior.
I don't know why the rule is that way, whether this is intentional, whether it is indeed a loophole, whether it's also violating another rule, how you're supposed to tell just by looking at it, etc... but regarding the question of whether it's UB: yes, it's undefined according to the standard.
I'm really annoyed by const keyword these days, as I'm not quite familiar with it. I had a vector that stores all const pointers like vector<const BoxT<T> *> *Q_exclude, and in the constructor of another class, I need an element in this queue to be passed in as a parameter and assign it to a non-const member. My question is:
How do I assign a const variable to a non-const variable? I know this doesn't make sense because after all, a const is a const, and should not be changed by any mean. But that annoying member variable REALLY has to be changed during the process! I might also change the data type in the vector to be non-const, but that would be too much work. Or does anyone know how to avoid such situation?
You can assign a const object to a non-const object just fine. Because you're copying and thus creating a new object, constness is not violated.
Like so:
int main() {
const int a = 3;
int b = a;
}
It's different if you want to obtain a pointer or reference to the original, const object:
int main() {
const int a = 3;
int& b = a; // or int* b = &a;
}
// error: invalid initialization of reference of type 'int&' from
// expression of type 'const int'
You can use const_cast to hack around the type safety if you really must, but recall that you're doing exactly that: getting rid of the type safety. It's still undefined to modify a through b in the below example:
int main() {
const int a = 3;
int& b = const_cast<int&>(a);
b = 3;
}
Although it compiles without errors, anything can happen including opening a black hole or transferring all your hard-earned savings into my bank account.
If you have arrived at what you think is a requirement to do this, I'd urgently revisit your design because something is very wrong with it.
Changing a constant type will lead to an Undefined Behavior.
However, if you have an originally non-const object which is pointed to by a pointer-to-const or referenced by a reference-to-const then you can use const_cast to get rid of that const-ness.
Casting away constness is considered evil and should not be avoided. You should consider changing the type of the pointers you use in vector to non-const if you want to modify the data through it.
The actual code to cast away the const-ness of your pointer would be:
BoxT<T> * nonConstObj = const_cast<BoxT<T> *>(constObj);
But note that this really is cheating. A better solution would either be to figure out why you want to modify a const object, and redesign your code so you don't have to.... or remove the const declaration from your vector, if it turns out you don't really want those items to be read-only after all.
Leaving this here for myself,
If I get this error, I probably used const char* when I should be using char* const.
This makes the pointer constant, and not the contents of the string.
const char* const makes it so the value and the pointer is constant also.
void SomeClass::changeASettingAndCallAFunction() const {
someSetting = 0; //Can't do this
someFunctionThatUsesTheSetting();
}
Another solution is to call said function in-between making edits to variables that the const function uses. This idea was what solved my problem being as I was not inclined to change the signature of the function and had to use the "changeASettingAndCallAFunction" method as a mediator:
When you call the function you can first make edits to the setting before the call, or (if you aren't inclined to mess with the invoking place) perhaps call the function where you need the change to the variable to be propagated (like in my case).
void SomeClass::someFunctionThatUsesTheSetting() const {
//We really don't want to touch this functions implementation
ClassUsesSetting* classUsesSetting = ClassUsesSetting::PropagateAcrossClass(someSetting);
/*
Do important stuff
*/
}
void SomeClass::changeASettingAndCallAFunction() const {
someFunctionThatUsesTheSetting();
/*
Have to do this
*/
}
void SomeClass::nonConstInvoker(){
someSetting = 0;
changeASettingAndCallAFunction();
}
Now, when some reference to "someFunctionThatUsesTheSetting" is invoked, it will invoke with the change to someSetting.
I can't find much information on const_cast. The only info I could find (on Stack Overflow) is:
The const_cast<>() is used to add/remove const(ness) (or volatile-ness) of a variable.
This makes me nervous. Could using a const_cast cause unexpected behavior? If so, what?
Alternatively, when is it okay to use const_cast?
const_cast is safe only if you're casting a variable that was originally non-const. For example, if you have a function that takes a parameter of a const char *, and you pass in a modifiable char *, it's safe to const_cast that parameter back to a char * and modify it. However, if the original variable was in fact const, then using const_cast will result in undefined behavior.
void func(const char *param, size_t sz, bool modify)
{
if(modify)
strncpy(const_cast<char *>(param), sz, "new string");
printf("param: %s\n", param);
}
...
char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true); // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true); // UNDEFINED BEHAVIOR
I can think of two situations where const_cast is safe and useful (there may be other valid cases).
One is when you have a const instance, reference, or pointer, and you want to pass a pointer or reference to an API that is not const-correct, but that you're CERTAIN won't modify the object. You can const_cast the pointer and pass it to the API, trusting that it won't really change anything. For example:
void log(char* text); // Won't change text -- just const-incorrect
void my_func(const std::string& message)
{
log(const_cast<char*>(&message.c_str()));
}
The other is if you're using an older compiler that doesn't implement 'mutable', and you want to create a class that is logically const but not bitwise const. You can const_cast 'this' within a const method and modify members of your class.
class MyClass
{
char cached_data[10000]; // should be mutable
bool cache_dirty; // should also be mutable
public:
char getData(int index) const
{
if (cache_dirty)
{
MyClass* thisptr = const_cast<MyClass*>(this);
update_cache(thisptr->cached_data);
}
return cached_data[index];
}
};
I find it hard to believe that that's the only information you could find about const_cast. Quoting from the second Google hit:
If you cast away the constness of an
object that has been explicitly
declared as const, and attempt to
modify it, the results are undefined.
However, if you cast away the
constness of an object that has not
been explicitly declared as const, you
can modify it safely.
What Adam says. Another example where const_cast can be helpful:
struct sample {
T& getT() {
return const_cast<T&>(static_cast<const sample*>(this)->getT());
}
const T& getT() const {
/* possibly much code here */
return t;
}
T t;
};
We first add const to the type this points to, then we call the const version of getT, and then we remove const from the return type, which is valid since t must be non-const (otherwise, the non-const version of getT couldn't have been called). This can be very useful if you got a large function body and you want to avoid redundant code.
The short answer is no, it's not safe.
The long answer is that if you know enough to use it, then it should be safe.
When you're casting, what you are essentially saying is, "I know something the compiler doesn't know." In the case of const_cast, what you are saying is, "Even though this method takes in a non-const reference or pointer, I know that it won't change the parameter I pass it."
So if you do actually know what you are claiming to know in using the cast, then it's fine to use it.
You're destroying any chance at thread-safety, if you start modifying things that the compiler thought were const.