This project is an attempt to bring smart pointer constructs to the (GNU) C programming language.
unique_ptr,shared_ptrmacros, andsmarttype attribute- Destructor support for cleanup
- Custom variable metadata on allocation
- Cross-platform: tested under linux 3.18.6-1, Mac OS X Yosemite 10.10, and Windows 7 (with MinGW and the Cygwin port of GCC)
Mac OS X:
brew install snaipe/soft/libcsptrAUR:
yaourt -S libcsptrUbuntu:
$ sudo add-apt-repository ppa:snaipewastaken/ppa $ sudo apt-get update $ sudo apt-get install libcsptr-dev
To compile the library, GCC 4.6+ is needed.
- Clone this repository
- run
mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PREFIX=$HOME .. && make && make install
from the project root for a local install, or runmkdir build && cd $_ && cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make && sudo make installfor a global install.
- Simple unique_ptr:
simple1.c:
Shell session:
#include<stdio.h>#include<csptr/smart_ptr.h>intmain(void) { // some_int is an unique_ptr to an int with a value of 1.smartint*some_int=unique_ptr(int, 1); printf("%p = %d\n", some_int, *some_int); // some_int is destroyed herereturn0; }
$ gcc -std=c99 -o simple1 simple1.c -lcsptr $ valgrind ./simple1 ==3407== Memcheck, a memory error detector ==3407== Copyright (C) 2002-2013, and GNU GPL\'d, by Julian Seward et al. ==3407== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info ==3407== Command: ./test1 ==3407== 0x53db068 = 1 ==3407== ==3407== HEAP SUMMARY: ==3407== in use at exit: 0 bytes in 0 blocks ==3407== total heap usage: 1 allocs, 1 frees, 48 bytes allocated ==3407== ==3407== All heap blocks were freed -- no leaks are possible ==3407== ==3407== For counts of detected and suppressed errors, rerun with: -v ==3407== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
- Simple unique_ptr with destructor:
#include<unistd.h>#include<fcntl.h>#include<csptr/smart_ptr.h>structlog_file { intfd; // ... }; voidcleanup_log_file(void*ptr, void*meta) { (void) meta; close(((structlog_file*) ptr)->fd); } intmain(void) { smartstructlog_file*log=unique_ptr(structlog_file, { .fd=open("/dev/null", O_WRONLY | O_APPEND), // ... }, cleanup_log_file); write(log->fd, "Hello", 5); // cleanup_log_file is called, then log is freedreturn0; }
- Allocating a smart array and printing its contents before destruction:
#include<stdio.h>#include<csptr/smart_ptr.h>#include<csptr/array.h>voidprint_int(void*ptr, void*meta) { (void) meta; // ptr points to the current element// meta points to the array metadata (global to the array), if any.printf("%d\n", *(int*) ptr); } intmain(void) { // Destructors for array types are run on every element of the// array before destruction.smartint*ints=unique_ptr(int[5], {5, 4, 3, 2, 1}, print_int); // ints == {5, 4, 3, 2, 1}// Smart arrays are length-awarefor (size_ti=0; i<array_length(ints); ++i) { ints[i] =i+1; } // ints == {1, 2, 3, 4, 5}return0; }
Using a different memory allocator (although most will replace malloc/free):
#include<csptr/smart_ptr.h>void*some_allocator(size_t); voidsome_deallocator(void*); intmain(void) { smalloc_allocator= (s_allocator) {some_allocator, some_deallocator}; // ...return0; }
Automatic cleanup on error cases:
#include<unistd.h>#include<fcntl.h>#include<csptr/smart_ptr.h>structlog_file { intfd; // ... }; staticvoidclose_log(void*ptr, void*meta) { (void) meta; structlog_file*log=ptr; if (log->fd!=-1) close(log->fd); } structlog_file*open_log(constchar*path) { smartstructlog_file*log=shared_ptr(structlog_file, {0}, close_log); if (!log) // failure to allocatereturnNULL; // nothing happens, destructor is not calledlog->fd=open(path, O_WRONLY | O_APPEND | O_CREAT, 0644); if (log->fd==-1) // failure to openreturnNULL; // log gets destroyed, file descriptor is not closed since fd == -1.returnsref(log); // a new reference on log is returned, it does not get destoyed } intmain(void) { smartstructlog_file*log=open_log("/dev/null"); // ...return0; // file descriptor is closed, log is freed }
Using named parameters:
#include<csptr/smart_ptr.h>voidnothing(void*ptr, void*meta) {} intmain(void) { struct { inta; } m= { 1 }; smartint*i=unique_ptr(int, .dtor=nothing, .value=42, .meta= { &m, sizeof (m) } ); return0; }
Q. Why didn't you use C++ you moron ?
A. Because when I first started this, I was working on a C project.
Also, because it's fun.
Q. Can I use this on a serious project ?
A. Yes, but as this project has not been widely used, there might be
some bugs. Beware!
Q. How did you make this ?
A. Here's a link to my blog post on the matter.