How to Use a C++ Smart Pointers Together with C's Malloc

Is it possible to use a C++ smart pointers together with C's malloc?

If you are using shared_ptr or unique_ptr, you can specify a custom deleter. For example,

struct free_delete
{
void operator()(void* x) { free(x); }
};

This can be used with shared_ptr like so:

std::shared_ptr<int> sp((int*)malloc(sizeof(int)), free_delete());

If you are using unique_ptr, the deleter is a part of the unique_ptr's type, so the deleter needs to be specified as a template argument:

std::unique_ptr<int, free_delete> up((int*)malloc(sizeof(int)));

However, it is better to use exceptions correctly, rather than avoiding them, when writing C++, especially with respect to allocation failures. In most cases, you cannot successfully recover from an allocation failure in the function trying to do the allocation, so exceptions can help you to handle the error where you are actually capable of handling it.

How to use smart pointer from function that returns a raw pointer

It depends. Consider this example:

struct example {
~example() { std::cout << "bye\n"; }
};

example* some_lib_function_A(){
return new example;
}

The library returns you a raw pointer to a dynamically allocated object. That's not nice, and to avoid dealing with the raw owning pointer you can wrap some_lib_function_A into a function that returns a smart pointer that manages the object.

However, the library might also do something along the line of this (just for the sake of the argument. It should rather return a reference):

example* some_lib_function_B() {
static example ex;
return &ex;
}

And in this case you cannot delete the returned pointer without running into problems.

Complete example:

#include <memory>
#include <iostream>
struct example {
~example() { std::cout << "bye\n"; }
};

example* some_lib_function_A(){
return new example;
}

example* some_lib_function_B() {
static example ex;
return &ex;
}

template <typename F>
std::unique_ptr<example> wrap(F f){
std::unique_ptr<example> res;
res.reset(f());
return res;
}

int main() {
wrap(some_lib_function_A);
wrap(some_lib_function_B); // free(): invalid pointer
}

The first line in main does what you would expect, but the second line causes undefined behavior. Thats the reason the linked answer says that it is bad to write a function along the line of:

 std::unique_ptr<example> wrap_bad(example& ex) {
std::unique_ptr<example> res;
res.reset(&ex);
return res;
}

Because you cannot know if the example passed to the function was dynamically allocated or not. The function is lying about what it does, because a function taking a reference has no business in dealing with lifetime of its parameter. It can be used correctly, but it has great potential to be used wrong.

You have to read the libraries documentation and find out what the library expects you to do with the pointer. Sometimes you must call some library function clean_up(ex) for proper clean up, in which case you can wrap the library clean up function in a custom deleter.

Use C++ shared_ptr to wrap C struct with deleter

The pointer which is managed by shared_ptr is not the same as original one - it's a copy of it. As a result, you create an object of std::shared_ptr which manages null pointer.

When you later call func on another copy of the same pointer, you change the value of original pointer, but the one managed by std::shared_ptr remains unchanged, and remains to be null.

Since there is no way to change the value of pointer managed by shared_ptr, the only way to solve this problem is to init your pointer before passing it over to std::shared_ptr for management.

How should I use an array of pointers of structs in C in my code below?

Compiling gives these warnings:

$ gcc Main.c A.c B.c -o out
B.c:5:8: warning: expression result unused [-Wunused-value]
b->x;
~ ^
B.c:6:8: warning: expression result unused [-Wunused-value]
b->y;
~ ^
2 warnings generated.

That leads almost directly to changing B.c to this:

#include "B.h"

B_ptr create_B(int x, int y) {
B_ptr b = (B_ptr)malloc(sizeof(B));
b->x = x;
b->y = y;
return b;
}

Then the output becomes:

$ ./out
x=1
y=2
x=2
y=3
x=3
y=4
x=4
y=5
x=5
y=6
x=6
y=7
x=7
y=8
x=8
y=9
x=9
y=10
x=10
y=11

malloc and freeing memory between threads in C

  • malloc() and free() are not thread-safe functions. You need to protect the calls to those functions with a mutex.
  • You need to protect all shared variables with a mutex as well. You can use the same one as you use for malloc/free, one per variable.
  • You need to declare variables shared between several threads as volatile, to prevent dangerous optimizer bugs on some compilers. Note that this is no replacement for mutex guards.
  • Are the buffers arrays, or two-dimensional arrays (like arrays of C strings)? You have declared all buffers as potential two-dimensional arrays, but you never allocate the inner-most dimension.
  • Never typecast the result of malloc in C. Read this and this.
  • free(bufferaction), not free(&bufferaction).
  • Initialize all pointers to NULL explicitly. After free(), make sure to set the pointer to NULL. Before the memory is accessed by either thread, make sure to check the pointer against NULL.

C linked list - when to free allocated memory

How do I go about freeing memory which has been allocated via malloc, while also returning the data to the caller?

Overall, the general rule in C memory management is that it must always be clear where the responsibility lies for freeing every piece of dynamically allocated memory, and wherever it does lie, that code must take care to fulfill all such responsibilities without fail. In your case, the only reasonable place to put the responsibility for freeing the struct _list_cell_t objects allocated for a given list is in the code that removes those objects from the list again (the pop, shift, and free functions).

After you free each such object, however, you must not access it again, so you must first store the data pointer you intend to return in a local variable. In fact, you already do this.

There are lots of ways to implement the details, but I suggest this paradigm:

  1. Store a pointer to the no-longer-needed struct _list_cell_t in a local variable.
  2. Update the structure of the list to cut out that object.
  3. Store a pointer to the wanted data in a local variable.
  4. Free the unneeded struct _list_cell_t via the pointer recorded in step (1)
  5. Return the data


Related Topics



Leave a reply



Submit