9

私にはあまり意味のないコンパイラ エラーが発生しました。

#include <memory>
using namespace std;

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

エラー: 'Table*' から非スカラー型 'std::auto_ptr< Table>' への変換が要求されました

ただし、次の行は機能します。

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」キーワードは、コンストラクターが暗黙的な型変換に使用されるのを防ぎます。次の 2 つの関数プロトタイプを検討してください。

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 に答える