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

Why auto_ptr initialization using the assignment syntax is not allowed

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

这是我无法理解的部分:

Note that class auto_ptr<> does not allow you to initialize an object with an ordinary pointer by using the assignment syntax.

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

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

无法使用赋值语法从原始指针初始化 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 构造函数上的显式 classifier。相反,您必须特意构造一个 auto_ptr 并将其传递给函数。

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

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

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

  1. I don't understand why it is not allowed.

乍一看直接初始化和复制初始化不是一回事

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

这是direct initialization

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

这是copy initialization

Copy-initialization is less permissive than direct-initialization: explicit constructors are not converting constructors and are not considered for copy-initialization.

所以如果你想通过复制初始化用原始指针初始化std::auto_ptr,将需要转换构造函数,但std::auto_ptr没有。

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

  1. What kind of pitfalls they were trying to avoid by not allowing initialization with assignment syntax

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

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

std::auto_ptr 的定义如下:

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

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

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