modern c++ 之我见

Posted on 2018-10-05 22:21:39

很俗套的标题

众所周知,c++1x为c++注入了大量现代化的的新特性,其中有些如nullptr、auto、Lambda,我已经能够熟练使用,有些则还处于一知半解。因此很有必要做一个私人的梳理。

弃用的旧特性

弃用并不是无法通过编译,而是鼓励程序员尽量避免使用。

char* 的字面常量赋值

应当使用const char * / auto

char * str = "h";             // Warning
const char * s  = "h";     //ok

C风格的类型转换

使用四个新的类型转换符取代之(详见effective c++ 条款27)

const_cast

顾名思义,移除指针或引用的const
特别注意

Pointers to functions and pointers to member functions are not subject to const_cast
Even though const_cast may remove constness or volatility from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const or to access an object that was declared volatile invokes undefined behavior.

函数指针显然不适用;通过非const路径修改const对象,是UB

#include <iostream>

struct type {
    int i;

    type() : i(3) {}

    void f(int v) const {
        // this->i = v;                 // 编译错误: this 是指向 const 的指针
        const_cast<type *>(this)->i = v; // 只要该对象不是 const 就 OK
    }
};

int main() {
    int i = 3; // 不声明 i 为 const
    const int &rci = i;
    const_cast<int &>(rci) = 4; // OK :修改 i
    std::cout << "i = " << i << '\n';    //i = 4

    const int j = 3; // 声明 j 为 const
    int *pj = const_cast<int *>(&j);
    *pj = 4; // UB
    std::cout << "j = " << j << '\n';    // j = 3
    std::cout << "*pj = " << *pj << '\n';    // *pj = 4

    void (type::*pmf)(int) const = &type::f; // 指向成员函数的指针
    // const_cast<void(type::*)(int)>(pmf);   // 编译错误: const_cast
    // 不在成员函数指针上工作
}
i = 4
j = 3
*pj = 4

static_cast

类似C风格的强制转换,静态类型转换,没有运行时的类型检查,存在安全隐患,可用于

  • 基本类型
  • 基类与子类的指针(或引用)转换,没有类型检查,不安全,审慎使用

    class Base {};
    class Derived : public Base {
    public:
      int i = 9;
    };
    
      Base *a = new Base;
      Base *b = new Derived;                               // 所谓upcast,也可以通过static_cast、dynamic_cast完成
      Derived *c = static_cast<Derived *>(a);    //通过编译,不安全
      std::cout << c->i << std::endl;    //UB 0
      c = static_cast<Derived *>(b);                  //安全,但不推荐
      std::cout << c->i << std::endl;    //1
      // c = dynamic_cast<Derived *>(a);    // error : 'Base' is not polymorphic
    

dynamic_cast

由上面示例中的编译错误可以看出,dynamic_cast用于运行时多态,安全的基类与子类的指针(引用)转换。

If expression is a pointer or reference to a polymorphic type Base, and new_type is a pointer or reference to the type Derived a run-time check is performed:
a) The most derived object pointed/identified by expression is examined. If, in that object, expression points/refers to a public base of Derived, and if only one subobject of Derived type is derived from the subobject pointed/identified by expression, then the result of the cast points/refers to that Derived subobject. (This is known as a “downcast”.)
b) Otherwise, if expression points/refers to a public base of the most derived object, and, simultaneously, the most derived object has an unambiguous public base class of type Derived, the result of the cast points/refers to that Derived (This is known as a “sidecast”.)
c) Otherwise, the runtime check fails. If the dynamic_cast is used on pointers, the null pointer value of type new_type is returned. If it was used on references, the exception std::bad_cast is thrown.

dynamic_cast可以做的:

  • downcast
    指向派生类对象的基类指针(引用)——> 派生类指针(引用)
  • sidecast
    指向派生类对象的基类指针(引用)——> 派生类的另一个基类指针(引用)
  • 检查失败,指针返回nullptr,引用抛出exception
#include <iostream>

struct V {
    virtual void f() {}; // must be polymorphic to use runtime-checked dynamic_cast
};
struct A : virtual V {};
struct B : virtual V {
  B(V* v, A* a) {
    // casts during construction (see the call in the constructor of D below)
    dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B*
    dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of B
  }
};
struct D : A, B {
    D() : B((A*)this, this) { }
};

struct Base {
    virtual ~Base() {}
};

struct Derived: Base {
    virtual void name() {}
};

int main()
{
    D d; // the most derived object
    A& a = d; // upcast, dynamic_cast may be used, but unnecessary
    D& new_d = dynamic_cast<D&>(a); // downcast
    B& new_b = dynamic_cast<B&>(a); // sidecast


    Base* b1 = new Base;
    if(Derived* d = dynamic_cast<Derived*>(b1))                // runtime check fails
    {
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // safe to call
    }

    Base* b2 = new Derived;
    if(Derived* d = dynamic_cast<Derived*>(b2))
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // safe to call
    }

    delete b1;
    delete b2;
}

结果:

downcast from b2 to d successful

reinterpret_cast

It is purely a compile-time directive which instructs the compiler to treat expression as if it had the type new_type.

处理无关类型转换的,通常为操作数的位模式提供较低层次的重新解释,但仅仅是重新解释了给出的对象的比特模型,并没有进行任何类型的检查和转换,可以用于不同类型的指针转换。