为什么auto_ptr构造不能使用= syntax

时间:2009-04-16 18:32:48

标签: c++ gcc stl auto-ptr

我遇到了一个对我没有多大意义的编译器错误:

#include <memory>
using namespace std;

auto_ptr<Table> table = db->query("select * from t");

错误:从'Table *'转换为非标量类型'std :: auto_ptr&lt;表&gt;”请求的

但是,以下行确实有效:

auto_ptr<Table> table(db->query("select * from t"));

构造函数的这个定义是什么阻止它像我期望的那样工作?我认为初始化的声明使用了构造函数。

这是我auto_ptr的构造函数(来自SGI STL):

explicit
auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }

4 个答案:

答案 0 :(得分:17)

这是“明确的”关键字。

template <typename T>
struct foo
{
  explicit foo(T const *)
  {
  }
};


template <typename T>
struct bar
{
  bar(T const *)
  {
  }
};


int main(int argc, char **argv)
{
  int a;
  foo<int> f = &a; // doesn't work
  bar<int> b = &a; // works
}

“explicit”关键字阻止构造函数用于隐式类型转换。考虑以下两个函数原型:

void baz(foo<int> const &);
void quux(bar<int> const &);

使用这些定义,尝试使用int指针调用这两个函数:

baz(&a);  // fails
quux(&a); // succeeds

在quux的情况下,你的int指针被隐式转换为一个条。

编辑:要扩展其他人评论的内容,请考虑以下(相当愚蠢)代码:

void bar(std::auto_ptr<int>);


int main(int argc, char **argv)
{
  bar(new int()); // probably what you want.

  int a;
  bar(&a); // ouch. auto_ptr would try to delete a at the end of the
           // parameter's scope

  int * b = new int();
  bar(b);
  *b = 42; // more subtle version of the above.
}

答案 1 :(得分:8)

您需要使用

auto_ptr<Table> table = auto_ptr<Table>(db->query("select * from t"));

auto_ptr没有为其模板类型定义赋值运算符。唯一允许的赋值来自另一个auto_ptr(它的指针构造函数是显式的)。这样做是为了保护auto_ptr的意外滥用,因为auto_ptr假设了内存的所有权。

我的猜测是你需要使用赋值表单来使用多个查询,如:

// initialize using constructor
auto_ptr<Table> table(db->query("select * from t1"));
...
// new query using assignment
table = auto_ptr<Table>(db->query("select * from t2"));
...
// another query using assignment
table = auto_ptr<Table>(db->query("select * from t3"));

答案 2 :(得分:5)

构造函数声明为显式,这意味着它不会用于隐式类型转换。由于auto_ptr占用了指针,因此隐式转换为auto_ptr很容易导致不良情况。

例如,如果auto_ptr允许从指针进行隐式转换,并且您意外地将指针传递给采用auto_ptr的方法,则指针将被静默转换为auto_ptr,并在函数结束时随后被删除,即使这不是意向。但是通过将构造函数标记为显式转换不能再以静默方式发生,并且通过调用构造函数,您可以清楚地表达将所有权传递给auto_ptr的意图,从而避免任何潜在的混淆。

void fun(std::auto_ptr<Foo> foo) // Assume implicit conversion is allowed.
{
    // do stuff with foo
}

Foo *foo = new Foo();

f(foo); // Normally this isn't allowed.

foo->bar(); // Oops

答案 3 :(得分:2)

添加到lothar所说的内容:因为auto_ptr构造函数是使用explicit关键字声明的,所以需要使用explict强制转换来从原始指针创建auto_ptr。 (在引入explicit之前,隐式转换是许多新的 - 经验丰富的)C ++开发人员的祸根。)