C++嵌套类使用注意事项

想在代码里通过嵌套类作为迭代器,访问外层类的数据。
主要是为了避免在头文件中包含STL头文件,编译时间伤不起

然后出现了神奇的bug,简化后代码如下:

class A {
public:
    class B {
    public:
        explicit B(void):idx(3){}
        B(const B&b)  {
            idx = 4;    // 不被调用
        }
    private:
        int idx=0;
    };
    B getB()
    {   return A::B();   }
};
void test2(){
    A a;
    A::B b = a.getB();  // b.idx 最终的值为 3
}

百思不得其解,google很久,最后得知c++11起添加了move操作避免复制临时对象和右值优化,c++17更是添加了Copy Elision

  • 临时对象优化(RVO, Returned Value Optimized)分两种,都需要满足临时对象同类型变量赋值条件:
    • 无名返回值优化(URVO, Unamed Returned Value Optimized) ,像代码中的A::getB()
    • 具名返回值优化(NRVO, UnamedReturned Value Optimized),类似于URVO,像A::getB(){B c; return c;}
  • 右值拷贝优化,临时对象被赋值给同类型对象时。

还是以代码举例

class A {
public:
    class B {
    public:
        explicit B(void):idx(3){}
        B(const B&b)  
        {   cout<<"copy"<<move;   }
        B(const B&&b)  // C++11添加的移动构造函数,配对是的移动赋值函数
        {   cout<<"move"<<move;   }
    private:
        int idx=0;
    };
    B getB()
    {   return A::B();   }
    B getB2()
    {   A::B c; return c;   }

};
void test2(){
    A a;
    A::B b = a.getB();  // 直接移动,**不调用复制,也不调用移动**
    A::B b = a.getB2();  // 调用移动构造函数
}

总结:

  1. 如果嵌套类对象可以有副本且包含指针变量,那么一定要使用共享型指针,如std::shared_ptr,不要用std::unique_str
  2. 本贴没有体现,直接说结论,嵌套类需要在dll外使用时,也要像正常类一样dllexport

C++标准说明
参考2
参考3
参考4

你可能感兴趣的:(c++)