Skip to content

Repository files navigation

C Smart Pointers

Build StatusCoverage StatusLicenseVersion

What this is

This project is an attempt to bring smart pointer constructs to the (GNU) C programming language.

Features

  • unique_ptr, shared_ptr macros, and smart type 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)

Installing

With a package manager

  • Mac OS X: brew install snaipe/soft/libcsptr

  • AUR: yaourt -S libcsptr

  • Ubuntu:

    $ sudo add-apt-repository ppa:snaipewastaken/ppa
    $ sudo apt-get update
    $ sudo apt-get install libcsptr-dev

Building from source

Prerequisites

To compile the library, GCC 4.6+ is needed.

Installation

  1. Clone this repository
  2. run mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PREFIX=$HOME .. && make && make install
    from the project root for a local install, or run
    mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make && sudo make install for a global install.

Examples

  • Simple unique_ptr: simple1.c:
    #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;
    }
    Shell session:
    $ 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;
    }

More examples

  • 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;
    }

FAQ

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.

About

Smart pointers for the (GNU) C programming language

Resources

Stars

1.7k stars

Watchers

57 watching

Forks

Releases

Packages

Used by

Contributors

Languages