简体   繁体   中英

Simple operator overload does not work

I have this code:

template <typename T>
class EasyPtr {
    T* data;
    public:
    EasyPtr(T* data): data(data){}
    EasyPtr(const EasyPtr<T>&)=delete;
    EasyPtr(EasyPtr<T>&&) = delete;
    ~EasyPtr(){
        delete data;
    }
    operator T*(){
        return data;
    }
    EasyPtr & operator = (T* data) {
        this -> data = data;
    }
    T& operator *() {
        return *data;
    }
    T& operator [](size_t pos) {
        return data[pos];
    }
};
int main(){
    EasyPtr<int> p = new int[10];
    return 0;
}

Surprisingly it gives error:

In file included from easy_ptr_test.cpp:1:0:
./easy_ptr.hpp:23:20: error: declaration of ‘operator[]’ as non-function
./easy_ptr.hpp:23:18: error: expected ‘;’ at end of member declaration
./easy_ptr.hpp:23:27: error: expected ‘)’ before ‘pos’
easy_ptr_test.cpp: In function ‘int main()’:
easy_ptr_test.cpp:4:32: error: use of deleted function ‘EasyPtr<T>::EasyPtr(EasyPtr<T>&&) [with T = int]’
In file included from easy_ptr_test.cpp:1:0:
./easy_ptr.hpp:10:5: error: declared here

It is apparently a function declaration... do not understand why. Maybe there is a stupid mistake somewhere.

The type size_t is defined in the cstddef header, so you should #include that before using it. That should get rid of the error surrounding the declaration of your operator[] .

The error in main arises because of the way copy-initialization works. When you do

EasyPtr<int> p = x;

you are performing copy-initialization . If x is of type EasyPtr<int> , or a cv-qualified version of it or one of its derived classes, then the effect of this initialization is simply to call either the copy or move constructor of EasyPtr<int> ( not the copy-assignment or move-assignment operator!) If x is of a different type, then x is first used to construct a temporary EasyPtr<int> object, and then the copy or move constructor of EasyPtr<int> is called to copy or move this temporary object into p . You are getting an error because the compiler wants to call the move constructor but you've deleted it. (Again, the copy-assignment and move-assignment operators are not called.)

Solutions:

1) explicitly define the move constructor

EasyPtr(EasyPtr<T>&& other): data(other.data) {
    other.data = nullptr;
}

2) explicitly default the move constructor (you probably don't want to do this for this particular class, because it'll lead to a double free, but this solution is included for the sake of completeness)

EasyPtr(EasyPtr<T>&&) = default;

3) use direct-initialization rather than copy-initialization

EasyPtr<int> p {new int[10]};

The last option is probably the one you want, since it looks like you don't want your objects to be copied or moved. In this case copy-initialization is just not going to work, so you should probably declare the converting constructor explicit , so the error message will be less confusing.

explicit EasyPtr(T* data): data(data){}
 EasyPtr<int> p = new int[10]; 

That line in main implicitly constructs a temporary EasyPtr<int> on the right-hand side. Conceptually, it looks like this:

 EasyPtr<int> p = EasyPtr<int>(new int[10]); 

This temporary can be moved into p . If your compiler implements copy-elision, the move of that temporary into p can even be elided; but in order for that to happen the move constructor still has to be accessible. Because the move constructor is declared as delete 'd, you receive the error. If you change it to EasyPtr<int> p(new int[10]) the error should go away because you're no longer constructing p from another EasyPtr instance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM