Есть ли у указателей конструкторы копирования?

Я перехожу с указателей C на C ++, теперь изучаю auto_ptr. Вот программа, которую я попробовал:

#include <iostream>
#include <memory>
#include "Car.h"using namespace std;
typedef auto_ptr<Car> CarPtr;
int main() {
CarPtr au_ptr1(new Car());
CarPtr au_ptr2 = new Car();
Car *norm_ptr1 = new Car();
Car *norm_ptr2(new Car());
int *i_ptr1=new int();
int *i_ptr2(new int());
}

Утверждения вроде следующего означают что?

int *i_ptr2(new int());
Car *norm_ptr2(new Car());

Упомянутое выше утверждение успешно скомпилировано. И следующее выдает ошибку компиляции: CarPtr au_ptr2 = new Car();
Это почему?

Заранее спасибо

0

Решение

У него есть конструктор копирования, но конструктор преобразования является явным, что является причиной ошибки:

explicit auto_ptr (X* p=0) throw();

Что означает Car* не может быть неявно преобразовано в auto_ptr<Car>, который является то, что

CarPtr au_ptr2 = new Car();

попытки сделать. Это называется копия инициализация, в отличие от:

CarPtr au_ptr1 (new Car());

который Значение инициализация. Первая версия попытается создать временную CarPtr из Car* и использовать его для инициализации au_ptr2, Второй вызывает конструктор копирования напрямую.

Заявления как

int *i_ptr2(new int());

просто инициализируйте значение указателя со значением в скобках.

1

Другие решения

Обычно объекты имеют конструктор копирования, а указатели не являются объектами, поэтому у них нет конструктора копирования (или оператора присваивания, или деструктора). Точнее, указатели полагаются на механизм копирования по умолчанию.

Когда вы говорите о auto_ptr или любые другие умные указатели, они просто однофамильцы указателей. Но на самом деле они Templatized объекты которые используют механизм RAII.

CarPtr au_ptr2 = new Car();  // this is initialization not assignment

дает ошибку компиляции, потому что соответствующий CarPtr::CarPtr(...) конструктор сделан explicitпоэтому он не принимает = инициализация стиля.

0

Необработанные указатели не имеют конструкторов, но для большинства целей их можно использовать так, как если бы они были. Все встроенные типы могут быть инициализированы из значения любого типа, преобразуемого в их тип, точно так же, как это может сделать пользовательский класс с конструктором копирования.

int *i_ptr1=new int();
int *i_ptr2(new int());

значит то же самое.

Я думаю, что причина этого в основном шаблоны: это означает, что вы можете использовать тип T как будто это был пользовательский тип, и напишите T t(0); или же T(0) или же T(), и когда T бывает встроенным типом значение точно такое же, как T t = 0; или же (T)0 или же (T)0 (снова). На самом деле, значение T(0) является по определению такой же как (T)0 независимо от того, какие конструкторы T имеет, но люди, которые говорят вам не использовать приведение в стиле C в коде C ++, пытаются игнорировать этот факт 😉

auto_ptr на самом деле имеет конструктор копирования, но, в отличие от большинства копий, он принимает неконстантный параметр и изменяет свой аргумент. Вот почему в C ++ 11 это устарело в пользу unique_ptr, который не имеет конструктора копирования, но имеет конструктор перемещения.

Как говорит Лучиан, проблема с CarPtr au_ptr2 = new Car(); это не (просто) конструктор копирования, это также отсутствие неявного преобразования из типа new Car();, Car*, чтобы auto_ptr<Car>, Инициализация копирования пытается неявно преобразовать RHS в тип LHS, а затем скопировать его в LHS. Оба из них терпят неудачу в этом примере. Прямая инициализация допускает использование явных преобразований и не требует копирования, поэтому она успешно выполняется.

Одним из способов, которым встроенные типы не ведут себя так, как будто они имеют конструкторы, является инициализация по умолчанию. Ты можешь написать:

int i = int();

а также i гарантированно инициализируется до нуля. Таким образом, вы можете представить, что у него есть конструктор без аргументов, который устанавливает его на ноль. Но если int были действительно тип класса с этим конструктором, а затем писать:

int i;

также гарантирует i ноль, и это не так (по крайней мере, не в области действия функции).

Кстати, не слишком волнуйтесь обо всем этом и случайно вызывайте так называемый «самый неприятный анализ».

int i();

эквивалентно int i(void);не int i(0);, Он объявляет функцию, а не целочисленную переменную.

0
По вопросам рекламы [email protected]