Почему конструкция auto_ptr не работает с использованием синтаксиса = - PullRequest
9 голосов
/ 16 апреля 2009

Я столкнулся с ошибкой компилятора, которая не имела для меня особого смысла:

#include <memory>
using namespace std;

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

ошибка: запрошено преобразование из 'Table *' в нескалярный тип 'std :: auto_ptr

Ответы [ 4 ]

17 голосов
/ 16 апреля 2009

Это "явное" ключевое слово.

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
}

Ключевое слово "явный" не позволяет конструктору использоваться для неявных преобразований типов. Рассмотрим следующие два прототипа функций:

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.
}
8 голосов
/ 16 апреля 2009

Вам нужно использовать

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"));
5 голосов
/ 16 апреля 2009

Конструктор объявлен как явный, что означает, что он не будет использоваться для неявного приведения типов. Неявное преобразование в 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
2 голосов
/ 16 апреля 2009

Добавление к сказанному Лотаром: поскольку конструктор auto_ptr объявлен с ключевым словом explicit, вам нужно использовать приведение экспликации для создания auto_ptr из необработанного указателя. (До введения explicit неявное приведение было проклятием многих новых и опытных разработчиков на C ++.)

...