简单的操作员过载不起作用

时间:2014-02-21 22:55:27

标签: c++ c++11

我有这段代码:

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;
}

令人惊讶的是它给出了错误:

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

这显然是一个功能声明......不明白为什么。也许某处有一个愚蠢的错误。

2 个答案:

答案 0 :(得分:2)

类型size_tcstddef标头中定义,因此在使用之前您应该#include。这应该摆脱你operator[]声明的错误。

main中的错误是由于复制初始化的工作方式而产生的。当你这样做

EasyPtr<int> p = x;

您正在执行复制初始化。如果x的类型为EasyPtr<int>,或者它的cv限定版本或其派生类之一,则此初始化的效果只是调用{{1的复制或移动构造函数(不是复制赋值或移动赋值运算符!)如果EasyPtr<int>属于不同类型,则x首先用于构造临时 x对象,然后然后调用EasyPtr<int>的复制或移动构造函数,以将此临时对象复制或移动到EasyPtr<int>。您收到错误,因为编译器想要调用移动构造函数但您已将其删除。 (同样,复制赋值和移动赋值运算符被调用。)

解决方案:

1)明确定义移动构造函数

p

2)显式默认移动构造函数(您可能不希望为此特定类执行此操作,因为它将导致双重释放,但为了完整性而包含此解决方案)

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

3)使用直接初始化而不是复制初始化

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

最后一个选项可能是您想要的选项,因为您似乎不希望复制或移动对象。在这种情况下,复制初始化不起作用,因此您应该声明转换构造函数EasyPtr<int> p {new int[10]}; ,因此错误消息将不那么混乱。

explicit

答案 1 :(得分:1)

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

main中的那一行隐含地构建了右侧的临时EasyPtr<int>。从概念上讲,它看起来像这样:

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

此临时文件可以移至p。如果您的编译器实现了copy-elision,那么将该临时文件移动到p甚至可以省略;但为了实现这一点,移动构造函数仍然必须是可访问的。因为移动构造函数声明为delete'd,所以您收到错误。如果您将其更改为EasyPtr<int> p(new int[10]),则错误应该消失,因为您不再从另一个p实例构建EasyPtr