Undefined behaviour with const_cast

前端 未结 7 2184
孤街浪徒
孤街浪徒 2020-12-19 01:37

I was hoping that someone could clarify exactly what is meant by undefined behaviour in C++. Given the following class definition:

class Foo
{
public:
             


        
相关标签:
7条回答
  • 2020-12-19 02:01

    Compilers may place const data in read only parts of memory for optimization reasons and attempt to modify this data will result in UB.

    0 讨论(0)
  • 2020-12-19 02:06

    Undefined behaviour depends on the way the object was born, you can see Stephan explaining it at around 00:10:00 but essentially, follow the code below:

    void f(int const &arg)
    {
        int &danger( const_cast<int&>(arg); 
        danger = 23; // When is this UB?
    }
    

    Now there are two cases for calling f

    int K(1);
    f(k); // OK
    const int AK(1); 
    f(AK); // triggers undefined behaviour
    

    To sum up, K was born a non const, so the cast is ok when calling f, whereas AK was born a const so ... UB it is.

    0 讨论(0)
  • 2020-12-19 02:08

    What is puzzling me is why this appears to work

    That is what undefined behavior means.
    It can do anything including appear to work.
    If you increase your optimization level to its top value it will probably stop working.

    but doesn't even prompt me with a warning to notify me that this behaviour is undefined.

    At the point it were it does the modification the object is not const. In the general case it can not tell that the object was originally a const, therefore it is not possible to warn you. Even if it was each statement is evaluated on its own without reference to the others (when looking at that kind of warning generation).

    Secondly by using cast you are telling the compiler "I know what I am doing override all your safety features and just do it".

    For example the following works just fine: (or will seem too (in the nasal deamon type of way))

    float aFloat;
    
    int& anIntRef = (int&)aFloat;  // I know what I am doing ignore the fact that this is sensable
    int* anIntPtr = (int*)&aFloat;
    
    anIntRef  = 12;
    *anIntPtr = 13;
    

    I know that const_casts are, broadly speaking, frowned upon

    That is the wrong way to look at them. They are a way of documenting in the code that you are doing something strange that needs to be validated by smart people (as the compiler will obey the cast without question). The reason you need a smart person to validate is that it can lead to undefined behavior, but the good thing you have now explicitly documented this in your code (and people will definitely look closely at what you have done).

    but I can imagine a case where lack of awareness that C-style cast can result in a const_cast being made could occur without being noticed, for example:

    In C++ there is no need to use a C style cast.
    In the worst case the C-Style cast can be replaced by reinterpret_cast<> but when porting code you want to see if you could have used static_cast<>. The point of the C++ casts is to make them stand out so you can see them and at a glance spot the difference between the dangerous casts the benign casts.

    0 讨论(0)
  • 2020-12-19 02:08

    A classic example would be trying to modify a const string literal, which may exist in a protected data segment.

    0 讨论(0)
  • 2020-12-19 02:10

    Static and const data are often stored in another part of you program than local variables. For const variables, these areas are often in read-only mode to enforce the constness of the variables. Attempting to write in a read-only memory results in an "undefined behavior" because the reaction depends on your operating system. "Undefined beheavior" means that the language doesn't specify how this case is to be handled.

    If you want a more detailed explanation about memory, I suggest you read this. It's an explanation based on UNIX but similar mecanism are used on all OS.

    0 讨论(0)
  • 2020-12-19 02:14

    Undefined behaviour literally means just that: behaviour which is not defined by the language standard. It typically occurs in situations where the code is doing something wrong, but the error can't be detected by the compiler. The only way to catch the error would be to introduce a run-time test - which would hurt performance. So instead, the language specification tells you that you mustn't do certain things and, if you do, then anything could happen.

    In the case of writing to a constant object, using const_cast to subvert the compile-time checks, there are three likely scenarios:

    • it is treated just like a non-constant object, and writing to it modifies it;
    • it is placed in write-protected memory, and writing to it causes a protection fault;
    • it is replaced (during optimisation) by constant values embedded in the compiled code, so after writing to it, it will still have its initial value.

    In your test, you ended up in the first scenario - the object was (almost certainly) created on the stack, which is not write protected. You may find that you get the second scenario if the object is static, and the third if you enable more optimisation.

    In general, the compiler can't diagnose this error - there is no way to tell (except in very simple examples like yours) whether the target of a reference or pointer is constant or not. It's up to you to make sure that you only use const_cast when you can guarantee that it's safe - either when the object isn't constant, or when you're not actually going to modify it anyway.

    0 讨论(0)
提交回复
热议问题