【问题标题】:Why auto_ptr initialization using the assignment syntax is not allowed为什么不允许使用赋值语法进行 auto_ptr 初始化
【发布时间】:2016-07-23 03:21:12
【问题描述】:

我正在阅读这本书 C++ standard library book

这是我无法理解的部分:

请注意,auto_ptr 类不允许您使用普通指针初始化对象 使用赋值语法。

std::auto_ptr<ClassA> ptr1(new ClassA); //ok
std::auto_ptr<ClassA> ptr2 = new ClassA; //error

我不明白为什么不允许这样做。他们试图通过不允许使用赋值语法进行初始化来避免什么样的陷阱

【问题讨论】:

    标签: c++ initialization auto-ptr


    【解决方案1】:

    赋值语法不能用于从原始指针初始化auto_ptr 的事实是构造函数的副作用,该构造函数将原始指针标记为显式。将构造函数标记为显式的通常原因是为了防止这样的事情:

    void take_ownership(std::auto_ptr<ClassA> ptr) {
        // the pointer is deleted when this function ends
    }
    
    void foo() {
        ClassA obj;
        take_ownership(&obj); // oops, delete will be called on a pointer to
                              // an object which was not allocated with new
    }
    

    由于std::auto_ptr 构造函数上的显式分类器,此处对take_ownership 函数的调用是错误的。相反,您必须故意构造一个 auto_ptr 并将其传递给函数。

    void foo() {
        std::auto_ptr<ClassA> ptr(new ClassA);
        take_ownership(ptr); // okay
    }
    

    当然,这并非完全不受滥用(您仍然可以将非新对象传递给auto_ptr 的构造函数),至少在滥用发生时更容易发现。

    顺便说一句,std::auto_ptr 已弃用。这是一个非常糟糕的课程(由于引入它时语言的限制)。请改用std::unique_ptr

    【讨论】:

      【解决方案2】:

      std::auto_ptr 的定义如下:

      template< class T > class auto_ptr;
      template<> class auto_ptr<void>;
      

      因此auto_ptr 是一个类类型。让我们看看它的构造函数:

      explicit auto_ptr( X* p = 0 );
      auto_ptr( auto_ptr& r );
      template< class Y >
      auto_ptr( auto_ptr<Y>& r );
      template< class Y >
      auto_ptr( auto_ptr_ref<Y> m );
      

      考虑第一个构造函数。我们可以使用指向X 类型对象的指针作为参数来调用这个构造函数:

      std::auto_ptr<X> ptr1(new X); //ok
      

      同时,第一个构造函数是explicit,因此我们不能使用指向X 类型对象的指针隐式转换为auto_ptr&lt;X&gt;。换句话说,我们不能通过指向X类型对象的指针直接初始化它。

          std::auto_ptr<X> ptr1 = new X; //error; cannot implicitly transform
      

      【讨论】:

      • 这解释了如何分配是不允许的,但它没有解释为什么
      【解决方案3】:
      1. 我不明白为什么不允许这样做。

      一开始直接初始化和复制初始化不是一回事。

      std::auto_ptr<ClassA> ptr1(new ClassA); //ok
      

      这是direct initialization

      std::auto_ptr<ClassA> ptr2 = new ClassA; //error
      

      这是copy initialization

      复制初始化比直接初始化更宽松:显式构造函数不转换构造函数并且不考虑复制初始化。

      因此,如果您想通过复制初始化使用原始指针初始化std::auto_ptr,则需要转换构造函数,但std::auto_ptr 没有。

      std::auto_ptrconstructor以一个原始指针为参数是explicit,禁止隐式转换。

      1. 他们试图通过不允许使用赋值语法进行初始化来避免什么样的陷阱

      如果允许隐式转换,请考虑以下代码:

      void f1(ClassA* p) { ... }
      void f2(std::auto_ptr<ClassA> p) { ... }
      ...
      ClassA* p = new ClassA;
      f2(p);           // call the wrong function, ownership is transfered to auto_ptr implicitly
      p->something(); // UB, p has been deleted
      delete p;       // UB
      

      【讨论】:

      • 请注意,对于您的示例,即使 p 被声明为正确初始化的 auto_ptr,然后以 f(p) 的形式传递给 f(将编译),下一行p-&gt;something() 仍然是 UB,因为 auto_ptr 是一个损坏的类。
      • @BenjaminLindley 是的。我想如果作者将p 明确声明为auto_ptr,他会意识到这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多