我正在阅读这本书 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">
我不明白为什么不允许这样做。他们试图通过不允许使用赋值语法进行初始化来避免哪些陷阱
答案 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)
- 我不明白为什么不允许这样做。
醇>
首先,直接初始化和复制初始化不是一回事。
std::auto_ptr<ClassA> ptr1(new ClassA); //ok
std::auto_ptr<ClassA> ptr2 = new ClassA; //error
复制初始化比直接初始化更不容许:显式构造函数不转换构造函数,不考虑复制初始化。
因此,如果您想通过复制初始化使用原始指针初始化std::auto_ptr
,则需要转换构造函数,但std::auto_ptr
没有。
std::auto_ptr
&#39; s constructor将一个原始指针作为参数explicit
,禁止隐式转换。
- 他们试图通过不允许使用赋值语法进行初始化来避免哪些陷阱
醇>
如果允许隐式转换,请考虑以下代码:
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