Я столкнулся со странной проблемой на С++, и я был бы признателен за объяснение. Этот фрагмент не компилируется:
size_t bufLength = 18;
char* buffer = new char[bufLength];
auto_array_ptr<char> pBuffer1 = buffer; // fails
auto_array_ptr<char> pBuffer2(buffer);
3-я строка выше не работает с No viable constructor copying variable of type 'auto_array_ptr<char>'
. Обратите внимание, что следующая строка компилируется просто отлично.
Q1) Это само по себе странно для меня. Я думал, что инициализация с присваиванием трансформируется в инициализацию с инициализатором, когда это необходимо. Почему первый может потерпеть неудачу, если второй успешен?
Q2) Но настоящая загадка для меня заключается в том, что ошибочная строка завершается успешно, когда я удаляю конструктор из класса auto_array_ptr
: конструктор auto_array_ptr(auto_array_ptr)
. Мне действительно трудно понять, что здесь происходит.
Я могу представить себе сценарий того, что компилятор может попытаться сделать здесь:
1- искать пустоту operator=(char *p)
. Не найден. Посмотрим, сможем ли мы продвигать аргумент (buffer
). 2- ах ах, есть operator=(auto_array_ptr&)
. Так что я выиграю, если смогу повысить buffer
до auto_array_ptr
. Давайте найдем конструктор для этого. 3- ах ах есть конструктор auto_array_ptr(auto_array_ptr&)
. Итак, давайте создадим временную переменную из buffer
, используя этот конструктор (temp
). 4- теперь попробуйте использовать метод operator=(auto_array_ptr&)
,. Но облом: его аргумент не const
, и я не могу его использовать. Сообщить об ошибке.
Но этот сценарий неубедителен. Во-первых, компилятор может заметить, что проблема const
— это шаг 2. Кроме того, он может использовать auto_array_ptr(char *)
напрямую, а не пытаться продвигать buffer
. Затем, если я добавлю в класс operator=(char *p)
, ошибка не исчезнет. Наконец, это не объясняет, почему удаление auto_array_ptr(auto_array_ptr&)
помогает.
Конечно, вам нужен источник auto_array_ptr
. вот:
template<class T>
class auto_array_ptr
{
public:
auto_array_ptr(T *p = 0) : ptr(p) {}
auto_array_ptr(auto_array_ptr<T>& a) : ptr(a.release()) {} // remove this line to compile
~auto_array_ptr() {if(ptr != 0) {delete[] ptr; ptr = 0;}}
void operator=(auto_array_ptr<T>& a) {if(&a != this) reset(a.release());}
// void operator=(T *p) { if(p != ptr) reset(p);} // adding this doesn't help
T& operator[](int i) const {return ptr[i];}
T& operator[](unsigned int i) const {return ptr[i];}
operator T*() const {return ptr;}
T* get() const {return ptr;}
T* release() {T* tmp = ptr; ptr = 0; return tmp;}
void reset(T *p = 0) {if(ptr != 0) {delete[] ptr;}; ptr = p;}
private:
T *ptr;
};
Компилятор представляет собой последнюю версию Clang, работающую в Xcode 4.4 под Mac OS X Lion. Я считаю, что он основан на LLVM 3.1. Чуть более свежая версия в Xcode 4.5 ведет себя точно так же.
Спасибо.