【发布时间】:2009-04-16 18:32:48
【问题描述】:
我遇到了一个对我来说没有多大意义的编译器错误:
#include <memory>
using namespace std;
auto_ptr<Table> table = db->query("select * from t");
错误:从 'Table*' 转换为非标量类型 'std::auto_ptr
我遇到了一个对我来说没有多大意义的编译器错误:
#include <memory>
using namespace std;
auto_ptr<Table> table = db->query("select * from t");
错误:从 'Table*' 转换为非标量类型 'std::auto_ptr
这是“显式”关键字。
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 指针被隐式转换为 bar。
编辑:要扩展其他人的评论,请考虑以下(相当愚蠢的)代码:
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.
}
【讨论】:
你需要使用
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"));
【讨论】:
auto_ptr<Table> table(db->query("select * from t"));?
构造函数被声明为显式,这意味着它不会用于隐式类型转换。隐式转换为 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
【讨论】:
补充一下lothar 所说的:因为auto_ptr 构造函数是用explicit 关键字声明的,所以您需要使用显式转换从原始指针创建auto_ptr。 (在引入 explicit 之前,隐式强制转换是许多新的和经验丰富的 C++ 开发人员的祸根。)
【讨论】: