The usage of const_cast in C++

Const_cast of the four types of conversions in C++

foreword

Quoting a passage from Clause 27 "Do as little transformation as possible" in **"Effective C++ Chinese Edition Third Edition"**:

One of the design goals of the C++ rules is to ensure that "type errors" are absolutely impossible to occur. In theory, if your program compiles "cleanly", it means that it does not attempt to perform any unsafe or meaningless operations on any object. , Stupid and absurd operation. This is an extremely valuable guarantee, so don't give it up hastily.

Unfortunately, casts break the type system, and that can lead to any kind of trouble, some easily recognizable, some very obscure.

 The reality is that it is 类型转换unavoidable in development. Before we start to discuss the type conversion of C++, let's look at C风格the type conversion first.

(T)varibale
T(variable)

 This is 旧式类型转换still often used, but 新式类型转换it should be used by us, because:

  • 1. It is easy to be identified, so it is easier to find the problem when the program goes wrong

  • 2. The division of responsibilities is more detailed, and the compiler is more likely to find problems during compilation.

  • 3. Stronger type conversion capability.

 The four new-style type conversions currently provided by C++ are

const_cast<T>()
dynamic_cast<T>()
reinterpret_cast<T>()
static_cast<T>()

 Let's const_caststudy it 用途and its applicable use separately 场景.

const_cast

const_cast<new type>(express)The main purpose of is 移除object 常量property, and it is the only C++-style cast operator with this capability

 In C++11, const_cast can complete the following type conversions

  • Two multi-level pointers that may point to the same type can be converted to each other, regardless of the cv properties (const and volatile) on each level.
  • A null pointer value can be converted to a null pointer value of the new type.

 It can be seen that const_cast mainly operates on pointers, and its capabilities can be roughly summarized as:

1. The constant pointer is converted into a non-constant pointer and still points to the original object;
2. The constant reference is converted into a non-constant reference and still points to the original object;

 The return result of const_cast can be distinguished as:

  • If new type is an lvalue reference, or an rvalue reference to a function type, then an lvalue is returned.
  • If new type is an rvalue reference to an object type, return xvalue.
  • Otherwise return prvalue.

 The following is an explanation of several values:

  • lvalue (Left-hand-side value)
  • rvalue (Right-hand-side value)
  • xvalue (eXpiring value)
  • prvalue (Pure rvalue)
  • glvalue (Generalized lvalue)

 For all the values, there were only two independent properties:

  • “has identity” – i.e. an address, a pointer, the user can determine whether two copies are identical, etc.use “i” represent
  • “can be moved from” – i.e. we are allowed to leave to source of a “copy” in some indeterminate, but valid state.use “m” represent.

 There are four possible composition:

  • iM: has identity and cannot be moved from (defined as lvalue)
  • im: has identity and can be moved from (defined as xvalue)
  • Im: does not have identity and can be moved from (defined as prvalue)
  • IM: doesn't have identity and cannot be moved (he thinks this case is useless in C++)

 The above is from https://cloud.tencent.com/developer/article/1493839

 It should be noted that in const_cast:

  1. pointer-to- 函数pointer and pointer-to-pointer 成员函数are not subject to const_cast.
  2. const_cast can form a reference or pointer to a non-const type, which actually refers to a const object, or a reference or pointer to a non-volatile type, which actually refers to a volatile object.
  3. The behavior that would result from modifying a const object through non-const access 路径and referencing a volatile object through a non-volatile glvalue 未定义.

未定义行为: The C++ standard does not make clear regulations on such behaviors. The same code will have different effects when using different compilers

《C++ Primer》and 《Effective C++》are essential books for C++ developers. If you want to get started with C++ and want to improve C++ development technology, these two books can be said to be necessary. In addition, 《Linux高性能服务器编程》and 《Linux多线程服务端编程:使用muduo C++网络库》.(陈硕)》is a cheat to quickly improve your linux development ability. It takes some effort to search for relevant resources on the Internet. Students who need it can pay attention to the official account【程序员DeRozan】 and reply **【1207】**Quick and free collection~

 Let's analyze the usage of const_cast through an example, the C++ version is C++11

1.new type is an lvalue reference

 Convert a const lvalue reference to a non-const lvalue reference:

 int i = 3; // i is not declared const
    const int &rci = i;
    const_cast<int &>(rci) = 4; // OK: modifies i
    std::cout << "i = " << i << '\n';

 console output

sh-4.4$ ./build/linux/x86_64/release/Class-convert 
i = 4

 That is, if the new type is 左值引用, the return value is one 左值.

2. new type is an rvalue reference of function type

 If the type of new type is 函数右值引用, the return value of const_cast is 左值.

void printHello(){
    
    
    cout<<"hello world"<<endl;
}

void printHello2(){
    
    
    cout<<"hello world 2"<<endl;
}

int main(){
    
    
    
    const std::reference_wrapper<void()>x = std::ref(printHello);
    // x = printHello2; //编译错误,const类型的函数右值引用
    const_cast<std::reference_wrapper<void()> &&>(x) = printHello2;  
    x();
}

3. new type is an rvalue reference of object type

 Convert a constant 对象右值引用to an 非常量object type reference:

class OBJ {
    
    
    public:
    int num;
    OBJ(int i){
    
    num = i;}
    ~OBJ(){
    
    }
};


int main()
{
    
    

    const OBJ&& obj = OBJ(1);
    cout<<"obj.num="<<obj.num<<endl;

    // obj.num = 3;  //编译错误,这里是const引用

    // const_cast<OBJ&&>(obj).num = 4;// 编译错误,error: using xvalue (rvalue reference) as lvalue
    // cout << "obj.num=" << obj.num<<endl;
    
    OBJ &&obj2 = const_cast<OBJ &&>(obj);  //编译通过
    obj2.num = 3;
    cout << "obj.num=" << obj.num << endl;
}

4. Pointers to functions and pointers to member functions are unconstrained

struct type
{
    
    
    int i;

    type() : i(3) {
    
    }

    void f(int v) const
    {
    
    
        // this->i = v;                 // compile error: this is a pointer to const
        const_cast<type *>(this)->i = v; // OK as long as the type object isn't const
    }
};
int main(){
    
    
      [[maybe_unused]] void (type::*pmf)(int) const = &type::f; // pointer to member function
    // const_cast<void(type::*)(int)>(pmf);   // compile error: const_cast does
    // not work on function pointers   
}

5. Modifying a const object through a non-const access path results in undefined behavior

    const int j = 3; // j is declared const
    [[maybe_unused]] int *pj = const_cast<int *>(&j);
    // *pj = 4;      // undefined behavior

6. const_cast can only be used to modify pointers, references

   const int j = 3; // j is declared const
   int ppj = const_cast<int>(j); // 编译错误,invalid use of const_cast with type ‘int’, which is not a pointer, reference, nor a pointer-to-data-member type

Guess you like

Origin blog.csdn.net/dddgggd/article/details/129339028