📜  如何制作一个只能动态分配对象的C++类?(1)

📅  最后修改于: 2023-12-03 15:08:30.768000             🧑  作者: Mango

如何制作一个只能动态分配对象的C++类?

在C++中,我们常常需要在堆上动态分配对象,但是有时候我们希望我们的类只能在堆上被动态分配,而不能在栈上被静态分配。这可以通过重载 newdelete 运算符来实现。

重载 new 和 delete

在C++中,我们可以通过重载 newdelete 运算符来实现堆上动态分配内存的方式。为了实现只能在堆上动态分配的类,我们需要重载全局的 newdelete 运算符,并在类内定义私有的 operator newoperator delete 运算符。

class HeapOnly {
public:
    void foo() {
        std::cout << "Hello, World!\n";
    }
private:
    void* operator new(std::size_t size);
    void operator delete(void* ptr);
};

void* HeapOnly::operator new(std::size_t size) {
    void* ptr = malloc(size);
    if (ptr == nullptr) {
        throw std::bad_alloc();
    }
    return ptr;
}

void HeapOnly::operator delete(void* ptr) {
    free(ptr);
}

int main() {
    // 尝试在栈上实例化 HeapOnly 类
    HeapOnly heapOnly; // 编译错误,HeapOnly 类不能在栈上实例化
    // 在堆上动态分配 HeapOnly 类的实例
    HeapOnly* heapOnlyPtr = new HeapOnly;
    heapOnlyPtr->foo(); // 输出 `Hello, World!`
    delete heapOnlyPtr;
    return 0;
}

在上面的代码中,我们重载了 HeapOnlynewdelete 运算符,使得我们的类只能在堆上被动态分配。

禁止拷贝和赋值

为了保证我们的类只能动态分配,我们还需要禁止拷贝和赋值。我们可以通过私有化拷贝构造函数和赋值运算符来实现:

class HeapOnly {
public:
    void foo() {
        std::cout << "Hello, World!\n";
    }

private:
    // 禁止拷贝和赋值
    HeapOnly(const HeapOnly&);
    HeapOnly& operator=(const HeapOnly&);

    void* operator new(std::size_t size);
    void operator delete(void* ptr);
};

void* HeapOnly::operator new(std::size_t size) {
    void* ptr = malloc(size);
    if (ptr == nullptr) {
        throw std::bad_alloc();
    }
    return ptr;
}

void HeapOnly::operator delete(void* ptr) {
    free(ptr);
}

int main() {
    // 尝试在栈上实例化 HeapOnly 类
    HeapOnly heapOnly; // 编译错误,HeapOnly 类不能在栈上实例化
    // 在堆上动态分配 HeapOnly 类的实例
    HeapOnly* heapOnlyPtr1 = new HeapOnly;
    HeapOnly* heapOnlyPtr2 = new HeapOnly(*heapOnlyPtr1); // 编译错误,禁止拷贝构造函数
    HeapOnly* heapOnlyPtr3 = new HeapOnly;
    *heapOnlyPtr3 = *heapOnlyPtr1; // 编译错误,禁止赋值运算符
    heapOnlyPtr1->foo(); // 输出 `Hello, World!`
    delete heapOnlyPtr1;
    delete heapOnlyPtr2;
    delete heapOnlyPtr3;
    return 0;
}
小结

通过重载 newdelete 运算符,并私有化拷贝构造函数和赋值运算符,我们可以实现只能在堆上动态分配的C++类。