Advertisement

C++ pointers that are released upon going out of scope

Started by February 13, 2025 05:02 PM
49 comments, last by taby 3 days, 3 hours ago

Yes, I did also mean it the way frob said it - I never use “new” directly, but most code that does not own the release of the ptr will obviously still get a pointer, or better yet, reference.

frob said:
so a raw pointer is best.

Actually, in C++, reference is best, unless “nullptr” is an actual valid parameter. I hope this is just lost in translation, but I see too many people still using pointers everywhere, even for non-nullable parameters, and it's really time this leftover C-nonsense is dorpped in C++ in 2025.
For things like arrays/strings we now have span/string_view… even less use-cases of actual *-ptrs. They do certainly exists, but way less in C++ than in C.

Thanks all. Should I be using vectors then?

Advertisement

if we work with malloc, may be you can use std::vector<byte>, for example

std::vector<byte> A; // instead of ‘char *A’
A.resize(<number of bytes>) // instead of A = malloc(<number of bytes>)
and get actual pointer by A.data(); or &A[0]
vector will be deleted once out of scope or assigned to another one, e.t.c

you can even write malloc and free, like:
std::vector<byte> malloc(int n) { return std::vector<byte>(n, 0); };
void free(std::vector<byte> &v) { v.clear(); }

None

Damn, implementing a malloc like that is awesome! Thanks for the insight, all!

RomanGenkhel said:
you can even write malloc and free, like:

std::vector malloc(int n) { return std::vector(n, 0); };

void free(std::vector &v) { v.clear(); }

Practically, but clear() may not free the reserved memory.

The only way i know to free for sure is:

void free(std::vector<byte> &v) 
{ 
	std::vector<byte> temp;
	std::swap(v, temp); 
}

(Even shrink_to_fit() is not guarantee, thus the swapping.)

@JoeJ Actually assignment is enough
A = std::vector<byte>();

taby said:

Damn, implementing a malloc like that is awesome! Thanks for the insight, all!

Also very useful type aliases like:
using MyData = std::vector<char>;

MyData MyPointer;

None

Advertisement

The only way i know to free for sure is:

Even that can be overcome with implementation details, like debug memory libraries, and overloads on new/delete family of functions.

The free store further complicates memory allocation and release, types can manage details of their own allocation and release. Usually it is as expected with the heap, but guarantees require looking at details. What you request from the system needs to be released back to the system, but what the system does isn't always specified. Just because your code says “I am done with this” doesn't mean the system is obligated to do something with it upon release, only the program code is bound to not use it any more.

Herb Sutter talks about the subtlety in Exceptional C++: Object lifetime can be less than the time the storage is allocated; that is, free store objects can have memory allocated without being immediately initialized, and can be destroyed without the memory being immediately deallocated. The short form is in http://www.gotw.ca/gotw/009.htm

But in general… Use smart pointers to indicate ownership. Use pointers (or references) if ownership isn't conveyed. Containers automatically manage resources, but even then it is important to understand object lifetime of everything you create / allocate, to ensure it is destroyed / released.

RomanGenkhel said:
you can even write malloc and free, like:
std::vector malloc(int n) { return std::vector(n, 0); };
void free(std::vector &v) { v.clear(); }

As someone with 20 years C++ experience, I would recommend against this. It's useless and just causes confusion by obfuscating what is actually happening. Why not just call std::vector(n,0) directly instead? If I saw this in a code review I would request changes.

  • It zeros the memory, which is useless and costs performance if you are going to immediately write non-zero contents.
  • Your malloc() takes an int instead of size_t, which is the size type used by STD containers. As a result, your code will break if you allocate more than 4 GB.
  • You rely on compiler return value optimization or move semantics to avoid an expensive reallocation and copy of the returned vector.
  • free() is also useless. Why not just call vector.clear()? Its more clear.
  • It overloads existing C functions which causes confusion. If I see someone calling a function called malloc() in C/C++, I expect it to take size_t input and return void*.
  • At the very least, these should be template functions to allow for changing the data type of the vector.

OK, one more question. I am trying to convert a vector<vector<char>> to **char, and all of the AIs told me to allocate and deallocate using new[] and delete[]. Here is the code:

#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;

// A test function taking in a pointer as a parameter, like many C functions do
void test_function(char **c, size_t size)
{

}

char** vectorToCharArray(const std::vector<std::vector<char>>& vec)
{
    // Allocate memory for rows

    char** arr = new char* [vec.size()];

    // Allocate and copy each row
    for (size_t i = 0; i < vec.size(); i++) {
        arr[i] = new char[vec[i].size() + 1];  // +1 for null terminator

        // Copy characters from vector to array
        for (size_t j = 0; j < vec[i].size(); j++) {
            arr[i][j] = vec[i][j];
        }

        // Add null terminator at the end of each row
        arr[i][vec[i].size()] = '\0';
    }

    return arr;
}

// Helper function to free the allocated memory
void freeCharArray(char** arr, size_t rows)
{
    for (size_t i = 0; i < rows; i++) {
        delete[] arr[i];
    }
    delete[] arr;
}

int main(void)
{
	size_t array_size = 5;

	// Vector method
	vector<vector<char>> vp(array_size);

    char** vp_ptrc = vectorToCharArray(vp);

	test_function(vp_ptrc, array_size);

    freeCharArray(vp_ptrc, array_size);

	// Both u_ptr and vector will automatically release their memory here,
	// as they go out of scope
	return 0;
}

Is there any way around this? Surely there's a way to make it so that I don't have to manually call freeCharArray()?

@Aressera 1. redefening ‘malloc’ with different return type cause nothing than compile time error, no memory corruption headache. Also, IMHO less changes in already existing C-style code is preferable, i even recommend use typedef for
char* / std::vector<char> and type casting overload to quick switch between C/C++ implementation

2. if we talking about performance (filling with zeros), better use A.resize(n) instead of assignment.
And you are right, filling with zeros is not necessary for ‘malloc’, may for 'calloc'
ps.
Its my opinion as 25+ years C/C++ programmer =) (don`t know why you mention it)

None

Advertisement