C ++ constructor prevents successful compilation

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; // fails auto_array_ptr<char> pBuffer2(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.

+4
source share
2 answers
 auto_array_ptr<char> pBuffer1 = buffer; // fails 

create temporary auto_array_ptr<char> from buffer and copy it to pBuffer1 .

 auto_array_ptr(auto_array_ptr<T>& a) 

your copy c-tor will get a reference . You cannot bind temporary to reference , so compilation fails.

Q2) But the real mystery to me is that the failed line succeeds when I remove the constructor from the auto_array_ptr class: auto_array_ptr (auto_array_ptr). It’s very hard for me to understand what is happening here.

The compiler will create copy c-tor using signature

 auto_array_ptr(const auto_array_ptr&) 
+4
source

This is copy initialization:

 auto_array_ptr<char> pBuffer1 = buffer; // fails 

This creates a temporary auto_array_ptr<char> from buffer , and then uses the constructor to copy for pBuffer1 . (subject to optimization) This fails because the copy constructor is declared as:

 auto_array_ptr(auto_array_ptr<T>& a) 

and temporary cannot link to const . Change it to

 auto_array_ptr(const auto_array_ptr<T>& a) 

This is direct initialization:

 auto_array_ptr<char> pBuffer2(buffer); 

uses conversion constructor.

+3
source

Source: https://habr.com/ru/post/1432083/


All Articles