为什么不允许使用赋值语法进行auto_ptr初始化

时间:2016-07-23 03:21:12

标签: c++ initialization auto-ptr

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

这是我无法理解的部分:

  

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

$ wget -qO- https://nvd.nist.gov/download/nvd-rss-analyzed.xml > result
$ firstline="<item rdf:about=\"https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-1977\""
$ firstline=$(echo $firstline | sed 's/\//\\&/g')
$ cat result | sed -n "/<item /,\${p; /$firstline/q;}"
  <item rdf:about="https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2007-3701">
  ...
  <item rdf:about="https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-1977">

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

3 个答案:

答案 0 :(得分:6)

赋值语法不能用于从原始指针初始化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
}

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

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

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

顺便说一下,std::auto_ptr已被弃用。这是一个非常破碎的类(由于引入时语言的限制)。请改用std::unique_ptr

答案 1 :(得分:2)

  
      
  1. 我不明白为什么不允许这样做。
  2.   

首先,直接初始化和复制初始化不是一回事。

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_ptr&#39; s constructor将一个原始指针作为参数explicit,禁止隐式转换。

  
      
  1. 他们试图通过不允许使用赋值语法进行初始化来避免哪些陷阱
  2.   

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

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

答案 2 :(得分: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<X>。换句话说,我们不能通过指向X类型对象的指针直接初始化它。

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