2
* Copyright (C) 2013 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
19
#ifndef GOBJ_MEMORY_H_
20
#define GOBJ_MEMORY_H_
22
#include<glib-object.h>
26
* This class is meant for automatically managing the lifetime of C objects derived
27
* from gobject. Its API perfectly mirrors the API of unique_ptr except that you
28
* can't define your own deleter function as it is always g_object_unref.
30
* API/ABI stability is not guaranteed. If you need to pass the object across an ABI
31
* boundary, pass the plain gobject.
33
* This is how you would use unique_gobj 99% of the time:
35
* unique_gobj<GSomeType> o(g_some_type_new(...));
37
* More specifically, the object will decrement the gobject reference count
38
* of the object it points to when it goes out of scope. It will never increment it.
39
* Thus you should only assign to it when already holding a reference. unique_gobj
40
* will then take ownership of that particular reference.
42
* Floating gobjects can not be put in this container as they are meant to be put
43
* into native gobject aware containers immediately upon construction. Trying to insert
44
* a floating gobject into a unique_gobj will throw an invalid_argument exception. To
45
* prevent accidental memory leaks, the floating gobject is unreffed in this case.
48
class unique_gobj final {
52
void validate_float(T *t) {
53
if(t != nullptr && g_object_is_floating(G_OBJECT(t))) {
54
throw std::invalid_argument("Tried to add a floating gobject into a unique_gobj.");
59
typedef T element_type;
61
typedef decltype(g_object_unref) deleter_type;
63
constexpr unique_gobj() noexcept : u(nullptr) {}
64
explicit unique_gobj(T *t) : u(t) {
65
// What should we do if validate throws? Unreffing unknown objs
66
// is dodgy but not unreffing runs the risk of
67
// memory leaks. Currently unrefs as u is destroyed
68
// when this exception is thrown.
71
constexpr unique_gobj(std::nullptr_t) noexcept : u(nullptr) {};
72
unique_gobj(unique_gobj &&o) noexcept { u = o.u; o.u = nullptr; }
73
unique_gobj(const unique_gobj &o) = delete;
74
unique_gobj& operator=(unique_gobj &o) = delete;
75
~unique_gobj() { reset(); }
77
deleter_type& get_deleter() noexcept { return g_object_unref; }
78
const deleter_type& get_deleter() const noexcept { return g_object_unref; }
80
void swap(unique_gobj<T> &o) noexcept { T*tmp = u; u = o.u; o.u = tmp; }
81
void reset(pointer p = pointer()) {
83
g_object_unref(G_OBJECT(u));
86
// Same throw dilemma as in pointer constructor.
91
T* release() noexcept { T* r = u; u=nullptr; return r; }
92
T* get() const noexcept { return u; }
94
T& operator*() const { return *u; }
95
T* operator->() const noexcept { return u; }
96
explicit operator bool() const noexcept { return u != nullptr; }
98
unique_gobj& operator=(unique_gobj &&o) noexcept { reset(); u = o.u; o.u = nullptr; return *this; }
99
unique_gobj& operator=(std::nullptr_t) noexcept { reset(); return *this; }
100
bool operator==(const unique_gobj<T> &o) const noexcept { return u == o.u; }
101
bool operator!=(const unique_gobj<T> &o) const noexcept { return u != o.u; }
102
bool operator<(const unique_gobj<T> &o) const noexcept { return u < o.u; }
103
bool operator<=(const unique_gobj<T> &o) const noexcept { return u <= o.u; }
104
bool operator>(const unique_gobj<T> &o) const noexcept { return u > o.u; }
105
bool operator>=(const unique_gobj<T> &o) const noexcept { return u >= o.u; }
109
void ::std::swap(unique_gobj<T> &f, unique_gobj<T> &s) noexcept { f.swap(s); }