I ran into a weird problem in C ++ and I would appreciate an explanation. This snippet does not compile:
size_t bufLength = 18; char* buffer = new char[bufLength]; auto_array_ptr<char> pBuffer1 = buffer;
Third line above with No viable constructor copying variable of type 'auto_array_ptr<char>' . Note that the next line compiles just fine.
Q1) This in itself is strange. I thought that initialization with assignment was converted to initialization using an initializer when necessary. Why can the first crash happen if the second succeeds?
Q2). But the real mystery to me is that the failed line succeeds when I remove the constructor from the auto_array_ptr class: the auto_array_ptr(auto_array_ptr) constructor auto_array_ptr(auto_array_ptr) . Itβs really hard for me to understand what is going on here.
I can imagine a script here that the compiler might try to do here:
1- look for the void operator=(char *p) . Not found. Let's see if we can advance the ( buffer ) argument. 2- ah ah, there is operator=(auto_array_ptr&) . So I win if I can push buffer to auto_array_ptr . Let's look at the constructor to do this. 3 ah ah there is a constructor auto_array_ptr(auto_array_ptr&) . So let's build a temporary variable from buffer using this constructor ( temp ). 4- now try using the operator=(auto_array_ptr&) method. But bummer: its argument is not const , and I cannot use it. Report an error.
But this scenario is not convincing. First, the compiler might notice that the const problem is step 2. In addition, it can use auto_array_ptr(char *) directly, rather than trying to push buffer . Then, if I add operator=(char *p) to the class, the error will not go away. Finally, this does not explain why removing auto_array_ptr(auto_array_ptr&) helps.
Of course you need the source auto_array_ptr . here he is:
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; };
The compiler is a recent version of Clang running on Xcode 4.4 under Mac OS X Lion. I believe this is based on LLVM 3.1. A slightly newer version in Xcode 4.5 behaves exactly the same.
Thanks.