Skip to content

om_unique_ptr

I&CG edited this page Jan 17, 2019 · 1 revision

om::unique_ptr

Overview:

Taking the ownership of a dynamically allocated object, controlling its lifetime. The object is destructed if the pointer root itself is destructed.

Since there are various way to get memory from heap, om::unique_ptr allows to specify a custom destructor in the template. The library provides already three of them:

#include <omMemory.h>

struct Foo {
  int food;
}

{ // starting some context
   ...
   om::unique_ptr<Foo> var0 = new Foo; // uses om::_element_destructor by default
   om::unique_ptr<Foo, om::_element_destructor> var1 = new Foo;
   om::unique_ptr<Foo, om::_array_destructor>   var2 = new Foo[5];
   om::unique_ptr<Foo, om::_allocs_destructor>  var3 = reinterpret_cast<Foo*>(malloc(sizeof(Foo)));

} // deletes all 4 objects using the correct destructors.

However, om::make_unique<T>(...) is not yet implemented. Its exception safety is probably not of priority in Arduino environments.

Public destructor methods:

  • om::_element_destructor uses delete,
  • om::_array_destructor uses delete[],
  • om::_allocs_destructor uses free() to clean up the heaps memory.

Some more examples:

   struct Position {
     int x, y, z;
   };

   om::unique_ptr<Position> p1 = new Position; // uses default om::_element_destructor
   p1->x = 2018;
	
   om::unique_ptr<float, om::_array_destructor> p2 = new float[20];
   p2[3] = 3.14159;
   p2[9] = p2[3] * 2.71;

   om::unique_ptr<char, om::_allocs_destructor> name = reinterpret_cast<char*>(malloc(64));
   memset(&(*name), 0, 64); 
   memset(name.get(), 0, 64); // same as above 

Methods:

  • unique_ptr();
    Construct empty pointer.

  • unique_ptr(T *ptr);
    Constructs pointer and owns the object of type T.

  • unique_ptr(unique_ptr &&other);
    Constructs pointer and owns from RValue-pointer. See move().

  • unique_ptr& operator=(unique_ptr &&other);
    Own object from RValue-pointer. Previously owned object instance is deleted. See move().

  • unique_ptr& operator=(T *ptr);
    Own object of type T. Previously owned object instance is deleted.

  • operator bool() const;
    Check if pointer is not nullptr;

  • T& operator* () const;
    Return reference to owned object instance, example: (*p1).x

  • T* operator-> () const;
    Return pointer to owned object instance, example: p1->x

  • T& operator[](uint32_t i) const;
    Return reference to i-th element in array, example: p2[3]

  • unique_ptr move();
    Returns new unique_ptr as RValue, (poor) replacement for missing std::move(). Grant ownership to RValue leaving a nullptr in this unique_ptr.

  • T* release();
    Releases ownership and returns pointer to object instance.

  • void swap(unique_ptr &other);
    Exchanges ownership between two unique_ptr.

  • T* get() const;
    Returns pointer, keep ownership.

  • void reset(T* ptr = nullptr);
    Drop ownership and free object instance. Take ownership of optionally provided new ptr. Operation is skipped, if ptr is already owned.

  • ~unique_ptr();
    Destructor: Drop ownership and free object instance. (That's why we're here...!)

Coding faults detected at compile time:

   om::unique_ptr<char, om::_allocs_destructor> name = reinterpret_cast<char*>(malloc(64));
   om::unique_ptr<char, om::_allocs_destructor> buffer;

   // buffer = name;                            
   // **** will fail during compile time, not allowed to duplicate ownership
   buffer.swap(name);                           // ok, exchanges ownerships

   // name = std::move(buffer);                 
   // **** will fail during compile time, not available
   name = buffer.move();                        // implemented instead with costs of one additional copy ...

   om::unique_ptr<char, om::_array_destructor> other = new char[100];
   // other.swap(name);
   // **** will fail during compile time, since destructors are not compatile!

   // om::unique_ptr<char> test = "abcd";
   // **** will fail during compile time, since compiler detects to delete a non-heap object!

If you would use a simple char* as variable most of the cases above would pass through until your projects crashes during runtime.

Clone this wiki locally