Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I know if I need to delete something in C++?

Imagine the following class:

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

I'm a bit confused about implementing a destructor for MyString. My first thought was that it would look like this:

~MyString() {
    delete [] str;
}

But how can I delete str if I can't be sure that it was allocated? For example, I could create an instance of MyString like this:

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

in which case I shouldn't delete str because it was not declared on the heap, but if I created an instance of MyString like this:

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

not deleting str would cause a memory leak (I assume) because it would be declared on the heap. But if I created an instance of MyString like this:

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

I shouldn't delete str because although it's on the heap, it hasn't been allocated; it just points to part of something else that's been allocated.

So how can I be sure that I'm not deleting something that I shouldn't be deleting or failing to delete something that needs to be deleted? Would the answer be different if MyString used char*s instead of const char*s? What if I used MyString my_string = new MyString...?

Edit: To clarify, I'm not actually writing a string class. I'm using a char array as a byte array. I assume std::string wouldn't work, since the bytes could be 0.

like image 971
EKW Avatar asked Dec 31 '16 05:12

EKW


People also ask

Is there a delete function in C?

The remove function in C/C++ can be used to delete a file. The function returns 0 if files is deleted successfully, other returns a non-zero value. Using remove() function in C, we can write a program which can destroy itself after it is compiled and executed.

Is delete a keyword in C?

delete keyword in C++ Delete is an operator that is used to destroy array and non-array(pointer) objects which are created by new expression. New operator is used for dynamic memory allocation which puts variables on heap memory. Which means Delete operator deallocates memory from heap.

How do I delete all contents of a file in C?

If the file is already open you can use freopen() function from stdio. h with "w" mode as it will first close the file and then reopen it for writing erasing whatever was in the file previously.

Is remove a system call?

remove isn't even a system call.


2 Answers

There are a couple different patterns that apply:

  1. The always-allocate pattern. In this approach, the class doesn't take ownership of the passed-in resource, rather it makes a copy in a buffer it allocated and therefore knows how to deallocate in its destructor. The original parameter is owned by the code calling the class, and that caller should clean up its own data whenever it wants, because the class instance has an independent copy. Example: std::string.

  2. The caller-specified-deleter pattern. In this approach, the class does take ownership, and to accomodate a variety of allocator/deallocator pairs, it accepts a parameter which is a function or function object that knows how to deallocate the data. The class destructor will call this deleter function/function object, performing the correct deallocation (or none at all) needed for that particular buffer. Example: std::shared_ptr.

  3. The nested-ownership pattern. Here, the class just keeps a pointer or reference to the original block of data. The caller still has ownership and the responsibility to free the data, but it additionally is required to keep that block valid for as long as the class instance it created exists. This is the lowest overhead at runtime, but also the most difficult to keep track of. Example: by-reference variable capture in a C++11 lambda.

Whichever of these you use for your class design, make sure you document it so the users of your class aren't left wondering.

like image 56
Ben Voigt Avatar answered Nov 15 '22 00:11

Ben Voigt


But how can I delete str if I can't be sure that it was allocated?

You can delete str only if:

  1. You document that you will be taking ownership of the pointer being passed to the constructor.

  2. You document that you will be calling delete on the memory passed to the constructor.

  3. Construct instances of the class only with memory allocated by call to new.

I would also recommend changing the class to use char* instead of 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 }
    {}
}

That would prevent accidental usages like:

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

And then, you have to make sure that you follow The Rule of Three.

like image 32
R Sahu Avatar answered Nov 15 '22 02:11

R Sahu