1 c++11使用大括号进行对象初始化—使用大括号编译器知道是调用构造函数来初化对象,不会出现语法上的误导认为是函数指针
    X another_X(X());//本意 用临时对象X()去调用移动构造函数去构造another_X这个对象,但是并没有调用移动构造!编译器会认为X another_X(X());这是一个函数声明,another_X是函数名,X是返回类型, 参数名 无 参数类型 函数指针,函数指针的返回类型为X 函数无参数。
    这是个很经典的c++ Most vexing parse” 问题。
    为了避免歧义c++11中,X another_X{ X{} };这样会调用移动构造函数
    smart_ptr ptr1{create_shape{shape_type::circle}};
    2 下面两个拷贝构造函数,一个泛型版本一个非泛型版本,但是函数体内容又都一致。应该只写一个泛型版本就够了啊,在调用拷贝构造时指明模板类型—如果没有非泛型版本的拷贝构造,则编译器给一个默认的拷贝构造,这样会导致相同类型的拷贝构造调用的是默认版一个堆上内存同时被两个指针拥有但是引用计数为1,这就是错误的。effective45条提到,member templates不影响语言规则,声明member templates用于泛化copy构造时,还需要声明正常的copy构造。
    smart_ptr ptr1; smart_ptr ptr2(ptr1);
    所以需要写非泛型版
    因为smart_ptr(smart_ptr&& other)这个函数不会被编译器当作移动构造函数,因而不会自动触发删除拷贝构造函数的行为。如果我们想要实现自动移动,需要显示地将拷贝构造函数标记为=delete,或者定义含模板参数的拷贝构造函数—所以要写含模板的拷贝构造函数

    1. smart_ptr(const smart_ptr& other)//拷贝构造
    2. {
    3. //使this 共享 other的资源
    4. ptr_ = other.ptr_;
    5. if (ptr_) {
    6. other.shared_count_
    7. ->add_count();//与other一样指向同一块资源 此资源的引用计数+1
    8. shared_count_ =
    9. other.shared_count_;
    10. }
    11. }
    12. template <typename U>
    13. smart_ptr(const smart_ptr<U>& other) noexcept //隐式类型转换(子类转父类) 拷贝构造
    14. {
    15. //使this 共享 other的资源
    16. ptr_ = other.ptr_;
    17. if (ptr_) {
    18. other.shared_count_
    19. ->add_count();
    20. shared_count_ =
    21. other.shared_count_;
    22. }
    23. }


    3 老师,能否推荐一些比较经典的C++开源项目,特别是关于后端开发的。
    作者回复: 23 到 27 讲的内容可以看一下。

    专注后端开发的,可以看 Boost.Asio。专栏讨论了 C++ REST SDK(其中用到了 Boost.Asio)。

    其他可以考虑的(没有用过,没有明确推荐):
    https://www.treefrogframework.org/
    https://www.webtoolkit.eu/wt
    http://pistache.io/
    https://github.com/ipkn/crow
    https://github.com/qicosmos/cinatra

    4 为什么shared_count类作为smart_ptr的内部类编译不过,而必须作为外部类呢?移进去的话,smart_ptr::shared_count 和 smart_ptr::shared_count 成了两个完全不相关的类型,它们的指针(在不做强制类型转换时)也不能互相赋值,不好。

    5 引入右值引用和移动构造后,用户要想用重载的 operator=,必须采用 other_ptr = std::move(some_ptr)右值或者 一个unique_ptr临时对象(比如函数返回unique_ptr)的方式,通过显示调用 std::move,让用户aware到 some_ptr 的内容已经被移动到 other_ptr 了,并且同时默认禁用了参数为左值引用的拷贝构造,导致 other_ptr = some_ptr 无法通过编译,就不会在使用时产生歧义了,这就是 unique_ptr 期望的语义—-
    unique_ptr的特点是只有一个unique_ptr能获得资源,为unique_ptr有名对象显示地加上move就说明用户以经显示地要抛弃这个有名对象了,可以将其资源通过op=转移到另一个unique_ptr,用户在使用时因为抛弃对象需要显示调用move 这么明显的调用,不会出现程序员在不知情的情况下抛弃了对象资源的情况