9

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

#include <memory>
using namespace std;

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

错误:请求从“表*”转换为非标量类型“std::auto_ptr<表>”

但是,以下行确实有效:

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

4 回答 4

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.
}
于 2009-04-16T18:38:33.557 回答
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"));
于 2009-04-16T18:35:48.820 回答
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
于 2009-04-16T19:01:12.613 回答
2

补充一下lothar 所说的:因为auto_ptr构造函数是用explicit关键字声明的,所以您需要使用显式转换来auto_ptr从原始指针创建一个。(在引入 之前explicit,隐式转换是许多新的和有经验的 C++ 开发人员的祸根。)

于 2009-04-16T18:39:28.780 回答