首页 文章

我怎么知道我是否需要删除C中的某些内容?

提问于
浏览
6

想象一下以下课程:

class MyString {
public:
    const char* str;
    std::size_t str_len;

    MyString(const char* str, std::size_t str_len)
        : str { str }
        , str_len { str_len }
    {}
}

我对为 MyString 实现析构函数感到有点困惑 . 我的第一个想法是它看起来像这样:

~MyString() {
    delete [] str;
}

但是如果我不能确定它是否被分配,我怎么能删除str?例如,我可以像这样创建 MyString 的实例:

const char* c_string = "Hello, World!";
MyString my_string(c_string, 13);

在这种情况下,我不应该删除 str ,因为它没有在堆上声明,但如果我创建了 MyString 的实例,如下所示:

char* char_array = new char[13]{'H','e','l','l','o',',',' ','W','o','r','l','d','!'};
MyString my_string(char_array, 13);

不删除 str 会导致内存泄漏(我假设),因为它将在堆上声明 . 但是如果我像这样创建一个 MyString 的实例:

char* char_array = new char[13]{'H','e','l','l','o',',',' ','W','o','r','l','d','!'};
MyString my_string(char_array + 3, 10);

我不应该删除 str 因为虽然已经分配了's on the heap, it hasn';它只是指向已经分配的其他东西的一部分 .

那么我怎样才能确定我是否删除或删除了需要删除的内容?如果MyString使用 char* 而不是 const char* s,答案会有所不同吗?如果我使用了 MyString my_string = new MyString... 怎么办?

Edit: 为了澄清,我__77701_ m使用char数组作为字节数组 . 我假设std :: string不起作用,因为字节可能是0 .

3 回答

  • 1

    有几种不同的模式适用:

    • 始终分配模式 . 在这种方法中,类不接受传入资源的所有权,而是在它分配的缓冲区中创建一个副本,因此知道如何在其析构函数中释放 . 原始参数由调用类的代码拥有,并且调用者应该在需要时清理自己的数据,因为类实例具有独立的副本 . 示例: std::string .

    • 调用者指定的删除模式 . 在这种方法中,类确实拥有所有权,并且为了容纳各种allocator / deallocator对,它接受一个参数,该参数是一个知道如何解除分配数据的函数或函数对象 . 类析构函数将调用此删除函数/函数对象,执行该特定缓冲区所需的正确释放(或根本不执行) . 示例: std::shared_ptr .

    • 嵌套所有权模式 . 这里,类只保留指向原始数据块的指针或引用 . 调用者仍然拥有所有权并且有责任释放数据,但是,只要它创建的类实例存在,它还需要保持该块有效 . 这是运行时最低的开销,但也是最难跟踪的开销 . 示例:C 11 lambda中的引用变量捕获 .

    无论您将哪种类型设计用于课堂设计,请务必记录下来,以便您的 class 用户不会感到疑惑 .

  • 10

    但是如果我不能确定它已被分配,我怎么能删除str?

    您只能在以下情况下删除 str

    • 您证明您将获得传递给构造函数的指针的所有权 .

    • 您证明您将在传递给构造函数的内存上调用 delete .

    • 仅使用通过调用 new 分配的内存构造类的实例 .

    我还建议更改类以使用 char* 而不是 const char* .

    class MyString {
    public:
        char* str;
        std::size_t str_len;
    
        MyString(char* str, std::size_t str_len)
            : str { str }
            , str_len { str_len }
        {}
    }
    

    这样可以防止意外使用:

    MyString my_string("Hello, World!", 13);
    

    然后,你必须确保你遵循The Rule of Three .

  • 1

    为了阐明界面,您可以使用适当的智能指针,例如:

    MyString(std::unique_ptr<const char[]> str, std::size_t str_len)
    

    或者,如果您没有获得所有权,请使用适当的字符串视图,例如:

    MyString(std::experimental::observer_ptr<const char> str, std::size_t str_len)
    

    然后你不再怀疑 class 的记忆政策 .

相关问题