From 7d166a70e075abde311eefa1ce341f802aa0048b Mon Sep 17 00:00:00 2001 From: Kp Date: Sun, 7 Sep 2014 21:23:03 +0000 Subject: [PATCH] Prevent accidental RAIIdmem construction --- SConstruct | 9 ++++ common/include/compiler-exchange.h | 15 ++++++ common/include/u_mem.h | 74 ++++++++++++++++-------------- common/ui/radio.cpp | 2 +- 4 files changed, 64 insertions(+), 36 deletions(-) create mode 100644 common/include/compiler-exchange.h diff --git a/SConstruct b/SConstruct index c7dc8674a..1bc036353 100644 --- a/SConstruct +++ b/SConstruct @@ -656,6 +656,15 @@ A *a(A &b) { if not self.check_cxx11_addressof(context, text=f) and not self.check_boost_addressof(context, text=f): raise SCons.Errors.StopError("C++ compiler does not support free function addressof().") @_custom_test + def check_cxx14_exchange(self,context): + f = ''' +#include "compiler-exchange.h" +int main(int argc,char**){ + return exchange(argc, 5); +} +''' + self.Cxx14Compile(context, text=f, msg='for C++14 exchange', successflags={'CPPDEFINES' : ['DXX_HAVE_CXX14_EXCHANGE']}) + @_custom_test def check_cxx14_integer_sequence(self,context): f = ''' #include diff --git a/common/include/compiler-exchange.h b/common/include/compiler-exchange.h new file mode 100644 index 000000000..645f8b765 --- /dev/null +++ b/common/include/compiler-exchange.h @@ -0,0 +1,15 @@ +#pragma once + +#include // for std::move or for std::exchange + +#ifdef DXX_HAVE_CXX14_EXCHANGE +using std::exchange; +#else +template +static inline T1 exchange(T1 &a, T2 &&b) +{ + T1 t = std::move(a); + a = std::forward(b); + return t; +} +#endif diff --git a/common/include/u_mem.h b/common/include/u_mem.h index ec7840881..67e0e4bec 100644 --- a/common/include/u_mem.h +++ b/common/include/u_mem.h @@ -24,6 +24,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #ifdef __cplusplus #include "dxxsconf.h" +#include "compiler-exchange.h" #include "compiler-type_traits.h" #define MEM_K 1.5 // Dynamic array growth factor @@ -57,22 +58,19 @@ static inline void mem_init(void) #endif template -T *MALLOC(std::size_t count, const char *var, const char *file, unsigned line) +T *MALLOC(T *&r, std::size_t count, const char *var, const char *file, unsigned line) { static_assert(tt::is_pod::value, "MALLOC cannot allocate non-POD"); - return reinterpret_cast(mem_malloc(count, var, file, line)); + return r = reinterpret_cast(mem_malloc(count, var, file, line)); } template -T *CALLOC(std::size_t count, const char *var, const char *file, unsigned line) +T *CALLOC(T *&r, std::size_t count, const char *var, const char *file, unsigned line) { static_assert(tt::is_pod::value, "CALLOC cannot allocate non-POD"); - return reinterpret_cast(mem_calloc(count, sizeof(T), var, file, line)); + return r = reinterpret_cast(mem_calloc(count, sizeof(T), var, file, line)); } -#define MALLOC( var, type, count ) (var=MALLOC((count)*sizeof(type),#var, __FILE__,__LINE__ )) -#define CALLOC( var, type, count ) (var=CALLOC((count),#var, __FILE__,__LINE__ )) - #define d_malloc(size) mem_malloc((size),"Unknown", __FILE__,__LINE__ ) #define d_calloc(nmemb,size) mem_calloc((nmemb),(size),"Unknown", __FILE__,__LINE__ ) #define d_realloc(ptr,size) mem_realloc((ptr),(size),"Unknown", __FILE__,__LINE__ ) @@ -87,47 +85,53 @@ static inline void d_free(T *&ptr) class BaseRAIIdmem { - BaseRAIIdmem(const BaseRAIIdmem&); - BaseRAIIdmem& operator=(const BaseRAIIdmem&); protected: - void *p; - BaseRAIIdmem() : p(NULL) {} - BaseRAIIdmem(void *v) : p(v) {} - ~BaseRAIIdmem() { - *this = NULL; - } - BaseRAIIdmem& operator=(void *v) + BaseRAIIdmem(const BaseRAIIdmem&) = delete; + BaseRAIIdmem& operator=(const BaseRAIIdmem&) = delete; + BaseRAIIdmem(BaseRAIIdmem &&that) : p(exchange(that.p, nullptr)) {} + BaseRAIIdmem& operator=(BaseRAIIdmem &&rhs) { - if (p != v) - { -#ifdef DEBUG_MEMORY_ALLOCATIONS - if (p) // Avoid bogus warning about freeing NULL -#endif - d_free(p); - p = v; - } + std::swap(p, rhs.p); return *this; } + void *p; + BaseRAIIdmem(void *v = nullptr) : p(v) {} + ~BaseRAIIdmem() { +#ifdef DEBUG_MEMORY_ALLOCATIONS + if (p) // Avoid bogus warning about freeing NULL +#endif + d_free(p); + } }; template -class RAIIdmem : public BaseRAIIdmem +struct RAIIdmem : BaseRAIIdmem { - RAIIdmem(const RAIIdmem&); - RAIIdmem& operator=(const RAIIdmem&); -public: static_assert(tt::is_pod::value, "RAIIdmem cannot manage non-POD"); - RAIIdmem() {} - RAIIdmem(T *v) : BaseRAIIdmem(v) {} + RAIIdmem() = default; + RAIIdmem(std::nullptr_t) : BaseRAIIdmem(nullptr) {} + explicit RAIIdmem(T *v) : BaseRAIIdmem(v) {} operator T*() const { return static_cast(p); } T *operator->() const { return static_cast(p); } - RAIIdmem& operator=(T *v) - { - BaseRAIIdmem::operator=(v); - return *this; - } }; +template +T *MALLOC(RAIIdmem &r, std::size_t count, const char *var, const char *file, unsigned line) +{ + T *p; + return r = RAIIdmem(MALLOC(p, count, var, file, line)); +} + +template +T *CALLOC(RAIIdmem &r, std::size_t count, const char *var, const char *file, unsigned line) +{ + T *p; + return r = RAIIdmem(CALLOC(p, count, var, file, line)); +} + +#define MALLOC( var, type, count ) (MALLOC(var, (count)*sizeof(type),#var, __FILE__,__LINE__ )) +#define CALLOC( var, type, count ) (CALLOC(var, (count),#var, __FILE__,__LINE__ )) + typedef RAIIdmem RAIIdubyte; typedef RAIIdmem RAIIdchar; #endif diff --git a/common/ui/radio.cpp b/common/ui/radio.cpp index 2564846ef..3eb97035a 100644 --- a/common/ui/radio.cpp +++ b/common/ui/radio.cpp @@ -76,7 +76,7 @@ UI_GADGET_RADIO * ui_add_gadget_radio( UI_DIALOG * dlg, short x, short y, short { auto radio = ui_gadget_add( dlg, x, y, x+w-1, y+h-1 ); - radio->text = d_strdup(text); + radio->text = RAIIdmem(d_strdup(text)); radio->width = w; radio->height = h; radio->position = 0;