为什么在std::auto_ptr的构造函数中使用了`explicit`关键字?

4
这是在VS2008编译器中使用的构造函数,用于从标准指针构造std::auto_ptr对象。
template<class _Ty>
class auto_ptr
{
   public:
   explicit auto_ptr(_Ty *_Ptr = 0) _THROW0() : _Myptr(_Ptr) {}

   private:
   _Ty *_Myptr;
};

为什么在上面使用了 explicit 关键字呢?是否有特别的原因?

换句话说,我为什么不能用下面这个方式初始化一个 auto_ptr 呢?

std::auto_ptr<Class A> ptr = new Class A;


重复的问题?https://dev59.com/00fRa4cB1Zd3GeqP7T2s - Bojan Komazec
4个回答

7
因为您可能会无意中执行以下操作:
void foo(std::auto_ptr<int> p)
{
}

void boo()
{
    int* p = new int();
    foo(p);
    delete p; // oops a bug, p was implicitly converted into auto_ptr and deleted in foo.... confusing
}

与您明确知道正在发生的情况相比:
void boo()
{
    int* p = new int();
    foo(std::auto_ptr<int>(p)); // aha, p will be destroyed once foo is done.
}

@Victor Nicollet:确实,我正在考虑是使用常量引用还是按值传递,但是卡在了中间:P... - ronag
但这也是一个错误:void boo() { int* p = new int; foo(std::auto_ptr<int>(p)); delete p; } - Ayrosa
2
@Ayrosa:如果你显式地构造一个 auto_ptr,然后尝试删除指针,那么你就会招来 bug。 如果构造是隐式的,你可能只是不知道发生了什么。 - Gorpik

2

构造一个std::auto_ptr是所有权的转移。对于所有涉及到的人来说,保持所有权的明确转移是最好的选择。例如:

void frobnicate(const std::auto_ptr<Class> & ptr);

Class *instance = new Class();
frobnicate(instance);
delete instance;

如果构造函数是隐式的,那么这段代码会编译通过,而不检查 frobnicate 的定义几乎不可能发现错误。此外,虽然使用 = 进行初始化现在更加困难,但你仍然可以使用其他初始化语法:
std::auto_ptr<Class> instance(new Class);
frobnicate(instance);

尽管 frobnicate 不能拥有对象,因为它接受一个 const 引用,但它需要按值接受指针。 - Mike Seymour
虽然 @MikeSeymour 的反对是有道理的,但我还是给他点赞,因为他提到了所有权转移,这也是构造函数需要明确声明的关键原因。 - Gorpik

1

首先,解决当前的问题,你可以像这样初始化:

std::auto_ptr<Class A> ptr(new A);

其次,隐式转换可能会带来更多的伤害而非好处,因此最好一开始就将构造函数设为显式调用单个参数,并仔细考虑是否需要隐式转换。


在我看来,最好的做法不是使那些构造函数显式,而是考虑是否希望进行隐式转换,然后采取相应措施。有很多有效的情况下,您实际上希望发生这些转换。 - Gorpik
@Gorpik:就像所有的“经验法则”一样,总有例外情况,但我发现在大多数情况下,隐式转换会带来更多的伤害而不是帮助。当你真正需要它时,添加一些重载函数会更简单。 - Matthieu M.
我认为这个规则比大多数其他规则都有更多的例外。但是我必须承认,默认情况下,这些构造函数应该被明确地声明。如果你说“除非你想要隐式转换,否则让它们明确”,我同意你的观点。 - Gorpik
1
@Gorpik: 没错,我已经相应地修改了答案。 - Matthieu M.

0

仅使用这个有什么问题吗:

std::auto_ptr<T> ptr(new T());

如果允许隐式转换,那么就可能会遇到各种问题,因为隐式转换会在最不期望的地方插入隐式转换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接