c++ - RAII - 类指针和作用域

标签 c++ design-patterns raii

我想通过一个例子更好地理解如何在我的类中实现 RAII 习惯用法:推荐的方法是什么来确保指针在我的类中是正确的 free()?

我有一个类(class),应该在类(class)期间存在。本着 RAII 的精神,并且因为我需要将对此类的引用传递给其他类,我将其保存在 shared_ptr 中(不确定它是否真的需要保存在 shared_ptr 中,但为了好玩,确实如此)。

在类 ctor 中,我使用 2 个缓冲区(指针)然后循环多次 malloc()'ing,使用缓冲区然后 free()'ing。 dtor 应包含故障安全代码以在发生事故时释放缓冲区。

dtor 可以看到缓冲区的唯一方法是将它们声明为类变量,但它们仅在类 ctor 中使用。

例子:

class Input
{
private:
    PSOMETYPE buffer1;
public:
    Input();
    ~Input();
}

Input::Input() : buffer1(NULL)
{
    for(blahblah)
    {
        buffer1 = (PSOMETYPE)malloc(sizeof(SOMETYPE));
        // Do work w/buffer1
        if(buffer1 != NULL) { free(buffer1); buffer1 = NULL }
    }
}

Input::~Input()
{
    if(buffer1 != NULL) { free(buffer1); buffer1 = NULL }
}

考虑到我只在 ctor 中使用缓冲区,将其声明为私有(private)类变量是否有意义?如果我在 ctor 的范围内声明它,dtor 将不知道要释放什么。

我知道这是一个微不足道的例子,老实说,我可以很容易地忘记使用智能指针来引用我的类并拥有一个空白的 dtor,就像我在循环中所做的那样 free()'ing 。我没有导师或学校教育,我不确定什么时候应该遵循 RAII 习语。

最佳答案

RAII 的精神是使用本地对象来管理本地分配的对象,而不是人为地将其生命周期绑定(bind)到正在构造的对象上:

class Input
{
    // no pointer at all, if it's only needed in the constructor
public:
    Input();
    // no explicit destructor, since there's nothing to explicitly destroy
};

Input::Input()
{
    for(blahblah)
    {
        std::unique_ptr<SOMETYPE> buffer1(new SOMETYPE);

        // or, unless SOMETYPE is huge, create a local object instead:
        SOMETYPE buffer1;

        // Do work w/buffer1
    }   // memory released automatically here
}

如果您正在编写一个目的是管理该资源的类,您应该只需要自己使用delete(或free,或其他)——通常已经有一个标准类(例如智能指针或容器)可以满足您的需求。

当您确实需要编写自己的管理类时,请始终记住 Rule of Three :如果你的析构函数删除了一些东西,那么类的默认复制行为几乎肯定会导致双重删除,所以你需要声明一个复制构造函数和复制赋值运算符来防止这种情况发生。例如,对于您的类(class),我可能会编写以下不正确的代码:

{
    Input i1;     // allocates a buffer, holds a pointer to it
    Input i2(i1); // copies the pointer to the same buffer
}                 // BOOM! destroys both objects, freeing the buffer twice

防止这种情况最简单的方法是删除复制操作,这样的代码将无法编译:

class Input {
    Input(Input const&) = delete;    // no copy constructor
    void operator=(Input) = delete;  // no copy assignment
};

旧的编译器可能不支持= delete;在这种情况下,您可以通过在不使用 = delete 的情况下私​​下声明它们并且不实现它们来获得几乎相同的效果。

关于c++ - RAII - 类指针和作用域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9687898/

相关文章:

c++ - 防止用户创建类的未命名实例

c++ - 如何在不创建新 int 的情况下设计 RAII 文件描述符

c++ - 直接初始化条件内的对象

c++ - 设置开始和结束限制以从文件中读取

c++ - Qt 异步 Action 序列

.net - 存储库模式是否过大?

c# - 单例反模式

c++ - 基于范围的for循环将对象 move 到另一个容器中?

c++ - 如何知道 jpeg 图像的压缩率?

c++ - 有共享引用计数智能指针这样的东西吗?