I ran into a compiler error that didn't make much sense to me:
#include <memory>
using namespace std;
auto_ptr<Table> table = db->query("select * from t");
error: conversion from 'Table*' to non-scalar type 'std::auto_ptr< Table>' requested
However, the following line does work:
auto_ptr<Table> table(db->query("select * from t"));
What is it about this definiton of the constructor that prevents it from working as I expect? I thought that initialized declarations used the constructors.
Here's my auto_ptr
's constructor (from the SGI STL):
explicit
auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }
It's the "explicit" keyword.
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
}
The "explicit" keyword prevents the constructor from being used for implicit type conversions. Consider the following two function prototypes:
void baz(foo<int> const &);
void quux(bar<int> const &);
With those definitions, try calling both functions with an int pointer:
baz(&a); // fails
quux(&a); // succeeds
In the case of quux, your int pointer was implicitly converted to a bar.
EDIT: To expand on what other people commented, consider the following (rather silly) code:
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.
}
You need to use
auto_ptr<Table> table = auto_ptr<Table>(db->query("select * from t"));
auto_ptr does not define an assignment operator for it's template type. The only allowed assignment is from another auto_ptr (and it's constructor from the pointer is explicit). This is done to protect accidental misuse of auto_ptr, as auto_ptr assumes ownership of the memory.
My guess is that you need the assignment form to use multiple queries after another like:
// 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"));
The constructor is declared as explicit, which means that it won't be used for implicit type casting. Implicit conversion to auto_ptr could easily lead to undesirable situations since the auto_ptr is taking ownership of the pointer.
For example, if auto_ptr would allow implicit conversion from a pointer and you accidentally passed a pointer to a method taking an auto_ptr the pointer would be silently converted to an auto_ptr and subsequently deleted when the function ends, even if that wasn't the intention. But by marking the constructor as explicit conversion can no longer happen silently and by calling the constructor you clearly express the intention of passing ownership to the auto_ptr, thus avoiding any potential confusion.
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
Adding to what lothar said: Because the auto_ptr
constructor is declared with the explicit
keyword, you need to use an explict cast to create an auto_ptr
from a raw pointer. (Before the introduction of explicit
, implicit casting was the bane of many a new -- and experienced) C++ developer.)
来源:https://stackoverflow.com/questions/757465/why-doesnt-auto-ptr-construction-work-using-syntax