Recently, I came across an example that my destructor needs to take a parameter.
I am working on a C package that manages memory internally and keeps track of allocating and freeing with parameters of its own. I do not want to break that.
I wrote a C code, that initializes my own data structures and frees them at the end. When I decided to migrate to C++ I realized that allocating data structures and freeing them should be placed in constructor and destructors. So I changed those functions to constructor and destructor.
My problem now is that I need to use a parameter to pass to destructor to free allocated data; that parameter is not in my own code and is C and I do not want to mess with that.
My question is twofold:
Why C++ decided not to accept parameters in destructors in the first place?
and
What are my options?
(I can save a pointer to that parameter or somehow call that function in my destructor, but it seems not a good practice of C++ programming)
Update: adding some code
Here is my imaginary class:
class paru_symbolic/* paru_symbolic*/
{
public:
paru_symbolic ( cholmod_sparse *A, cholmod_common *cc ); // constructor
~paru_symbolic (cholmod_common *cc ); // destructor
// -------------------------------------------------------------------------
// row-form of the input matrix and its permutations
// -----------------------------------------------------------------------
//--- other stuff
...
};
Here is my current C constructor:
#include "Parallel_LU.hpp"
paru_symbolic *paru_sym_analyse
(
// inputs, not modified
cholmod_sparse *A,
// workspace and parameters
cholmod_common *cc ){
DEBUGLEVEL(0);
...
aParent = (Int*) paru_alloc (m+nf, sizeof(Int),cc);
...
}
and destructor:
void paru_freesym (paru_symbolic **LUsym_handle,
// workspace and parameters
cholmod_common *cc
){
DEBUGLEVEL (0);
if (LUsym_handle == NULL || *LUsym_handle == NULL){
// nothing to do; caller probably ran out of memory
return;
}
paru_symbolic *LUsym;
LUsym = *LUsym_handle;
Int m, n, anz, nf, rjsize;
...
cholmod_l_free (m+nf, sizeof (Int), LUsym->aParent, cc);
...
cholmod_l_free (1, sizeof (paru_symbolic), LUsym, cc);
*LUsym_handle = NULL;
}
The parameter cc is used inside the SuiteSparse package for tracking allocations and freeing data. It has been used all over in SuiteSparse package and is a useful tool for tracking memory.
Some people mentioned that who wants to pass a parameter to the destructor.That is a fair point, but we could have the same parameters that we have in the constructor as a default.
Parameters in destructors do not make sense as destructors are automatically invoked when an object goes out of scope. How could you pass a parameter to that?
{
Foo x;
} // `~Foo()` is automatically called here
What you probably want is to store the resource in your class. Here's an unrealistic example with a dynamically-allocated pointer:
struct RAIIPointer
{
Foo* ptr;
// Initialize the resource
RAIIPointer() : ptr{new Foo{/*...*/}}
{
}
RAIIPointer(const RAIIPointer&) = delete;
RAIIPointer& operator=(const RAIIPointer&) = delete;
RAIIPointer(RAIIPointer&&) { /* implement appropriately */ }
RAIIPointer& operator=(RAIIPointer&&) { /* implement appropriately */ }
// Release the resource
~RAIIPointer()
{
delete ptr;
}
};
Note that in a real-world scenario you would use std::unique_ptr, and if you were implementing your own RAII resource class you would need to implement proper copy/move operations.
#Vittorio's answer has the general approach. I'll just tailor it to your added sample code.
The way you presented the issue is as follows:
You use a utility type cholmod_common to do some useful work for your type.
The instance of that type can be passed to several paru_symbolic objects you create.
No single instance of paru_symbolic owns it uniquely, but they all depend on it at the start and end of their lifetime. It must exist for the same duration as all of those objects.
That screams std::shared_ptr to me.
class paru_symbolic
{
std::shared_ptr<cholmod_common> _cc;
public:
paru_symbolic ( cholmod_sparse *A, std::shared_ptr<cholmod_common> cc)
: _cc(cc) {
// constructor
}
~paru_symbolic () {
// use _cc , it's guaranteed to live until the closing brace at the least.
}
};
That's it. The ownership is now shared. The last object that depends on the instance of cholmod_common will be the one to clean it up with no extra work from you.
In C++, this sort of thing is done via an allocator, see also std::allocator. So, you could create your own allocator with a cholmod_common* data member.
Alternatively, you can use the deleter parameter for memory management via smart pointers. For example
class foo
{
struct bar_deleter {
cholmod_common *cc;
bar_deleter(cholmod_common *c) : cc(c) {}
void destroy(bar*) { cc->free(bar); }
};
std::unique_ptr<bar,bar_deleter> data;
public:
foo(some_type const&input, cholmod_common *cc)
: data(cc->create<bar>(input), bar_deleter(cc)) {}
};
Which, of course, also keeps a cholmod_common* with the data.
The name "cholmod_common" suggests that this is a common resource, i.e. there is only one cholmod_common object at any given time. Iff this is so, then you could use a stateless allocator, which keeps the common resource as a static data member (or obtains it via a singleton).
Related
There is a little code example here:
struct Data {
};
struct Init {
Data *m_data;
Init() : m_data(new Data) { }
~Init() {
delete m_data;
}
};
class Object {
private:
int m_initType;
Data *m_data;
public:
Object(const Init &init) : m_initType(0), m_data(init.m_data) { }
Object(Init &&init) : m_initType(1), m_data(init.m_data) { init.m_data = nullptr; }
~Object() {
if (m_initType==1) {
delete m_data;
}
}
};
Object can be initialized two ways:
const Init &: this initialization just stores m_data as a pointer, m_data is not owned, so ~Object() doesn't have to do anything (in this case, m_data will be destroyed at ~Init())
Init &&: this initialization transfers ownership of m_data, Object becomes the owner of m_data, so ~Object() needs to destroy it
Now, there is a function:
void somefunction(Object object);
This function is called in callInitA and callInitB:
void callInitA() {
Init x;
somefunction(x); // calls the "const Init &" constructor
}
void callInitB() {
somefunction(Init()); // calls the "Init &&" constructor
}
Now, here's what I'd like to accomplish: in the callInitA case, I'd like to make the compiler to optimize away the destructor call of the resulting temporary Object (Object is used frequently, and I'd like to decrease code size).
However, the compiler doesn't optimize it away (tested with GCC and clang).
Object is designed so it doesn't have any functions which alter m_initType, so the compiler would be able to find out that if m_initType is set to 0 at construct time, then it won't change, so at the destructor it is still be 0 -> no need to call destructor at all, as it would do nothing.
Even, m_initType is an unnecessary member of Object: it is only needed at destruct time.
Do you have any design ideas how to accomplish this?
UPDATE: I mean that using some kind of c++ construct (helper class, etc.). C++ is a powerful language, maybe with some kind of c++ trickery this can be done.
(My original problem is more complex that this simplified one: Object can be initialized with other kind of Init structures, but all Objects constructors boils down to getting a "Data*" somehow)
void callInitA() {
Init x;
somefunction(x); // calls the "const Init &" constructor
}
The destruction of x cannot be optimized away, regardless of the contents of Init. Doing so would violate the design of the language.
It's not just a matter of whether Init contains resources or not. Init x, like all objects, will allocate space on the stack that later needs to be cleaned up, as an implicit (not part of code that you yourself write) part of the destructor. It's impossible to avoid.
If the intention is for x to be an object that somefunction can call without having to repeatedly create and delete references to x, you should be handling it like this:
void callInitA(Init & x) { //Or Init const& x
somefunction(x); // calls the "const Init &" constructor
}
A few other notes:
Make sure you implement the Rule of Five (sometimes known as Rule of Three) on any object that owns resources.
You might consider wrapping all pointers inside std::unique_ptr, as it doesn't seem like you need functionality beyond what std::unique_ptr offers.
Your m_initType actually distinguishes between two kinds of Objects - those which own their memory and those which don't. Also, you mention that actually there are many kinds of Objects which can be initialized with all sorts of inputs; so actually there are all sorts of Objects. That would suggest Object should better be some abstract base class. Now, that wouldn't speed anything up or avoid destructor calls, but it might make your design more reasonable. Or maybe Object could be an std::variant (new in C++17, you can read up on it).
But then, you say that temporary Objects are "used frequently". So perhaps you should go another way: In your example, suppose you had
template <bool Owning> class Object;
which you would then specialize for the non-owning case, with only a const Init& constructor and default destruction, and the owning case, with only an Init&& constructor (considering the two you mentioned) and a destructor which deletes. This would mean templatizing the code that uses Object, which many mean larger code size, as well as having to know what kind of Objects you pass in; but if would avoid the condition check if that really bugs you so much.
I'd like to decrease code size
I kind of doubt that you do. Are you writing code for an embedded system? In that case it's kind of strange you use lots of temporary Objects which are sort-of polymorphic.
Inside a method can one create an uninitialised object from the class?
Here's some context: imagine a class where the constructors all allocate memory:
class NumberArray
{
size_t m_Size;
int *m_Numbers;
public:
NumberArray() { m_Size = 1; m_Numbers = new int[1]; m_Numbers[0] = 0; }
// . . . other methods for manipulating or constructing . . .
~NumberArray() { delete[] m_Numbers; }
// What if I had a method that concatenates two arrays?
NumberArray ConcatenateWith(const NumberArray &) const;
};
Inside such a method one would desire to create an uninitialised object of class NumberArray, and then 'construct' a new object based on this and the object in the parameter? AKA:
NumberArray NumberArray::ConcatenateWith(const NumberArray &other) const
{
// Mystery manner of creating an uninitialised NumberArray 'returnObject'.
returnObject.m_Size = m_Size + other.m_Size;
returnObject.m_Numbers = new int[returnObject.m_Size];
std::copy(m_Numbers, m_Numbers + m_Size, returnObject.m_Numbers);
std::copy(other.m_Numbers, other.m_Numbers + other.m_Size, returnObject.m_Numbers + m_Size);
return returnObject;
}
What's the best way of doing this? Basically, I don't want the default constructor to create a size 1 array that I will just delete and then allocate a new array for again anyway.
It's not entirely clear what you are trying to do, but if all you want is to create a new instance of the class and not have a constructor other than the default constructor called then do just that.
All you have to do is create a private constructor, that has a different signature from the default constructor and which does not allocate memory (or differs in whatever way you need it to differ from the default constructor); then simply have your class invoke that constructor internally, when necessary.
What you're asking for is placement new. This looks something like this:
#include <cstdlib>
#include <new>
void* mem = std::malloc(sizeof(T)); // memory for a T (properly aligned per malloc)
T* x = new (mem) T; // construct a T in that memory location
x->~T(); // destruct that T
std::free(mem); // and free the memory
Doing this correctly (in an exception-safe manner with properly managed and aligned memory) is not a trivial task. You need to be careful about the lifetime of your objects.
For your question, you are describing exactly what std::vector does. It allocates raw uninitialized memory and constructs inserted elements directly into that memory. And lots of its code is dedicated to just getting the lifetime and memory management correct and exception safe!
You should strongly prefer to use std::vector instead of writing it yourself.
There is no well-defined way, as far as I'm aware, to create an object without invoking it's constructor. This is regardless of whether you have access to its public interface or not, though you could implement a private or protected constructor if you want to restrict who can invoke it. There is otehrwise no restrictions on creating new instances of a class from its own internal methods, in fact it is quite common to define a private constructor and a static public method that create instances of said object if you want to restrict under which conditions said object can be created.
If you want to, you can allocated sufficient memory for an object and reinterpret_cast a pointer to that memory to a pointer of the type you want. This usually works for POD's, but since many implementations (if not all) of polymorphic inheritance in c++ adds a pointer to a vtable to polymorphic instances this approach will usually, if not always, fail for those.
In short, create a private constructor and have a static method invoke it and then do any other work that you need is my recommendation.
I think this may be similar to what you want, an 'anonymous' class of sorts:
struct test {
virtual void doSomething() {
puts("test");
}
};
struct a {
test *t() {
struct b : test {
void doSomething() {
puts("b");
};
};
return new b;
};
};
int main()
{
a a;
a.t()->doSomething(); // outputs 'b'
}
However, due to slicing and how new works on C++, you must return a pointer and the 'anonymous' type must have a name, even if it's restricted only to the function.
If you could edit the OP and clarify exactly what you wish to accomplish by this, maybe we could help you more.
I'm new to the C++ world, but I have some experience with C and read some tutorials about C++.
Now, creating objects in C++ seems quite easy and works well for me as long as the class has only attributes that are values (not pointers).
Now, when I try to create objects which allocate memory in the constructor for some of their attributes, I figure out how exactly such objects are passed between functions.
A simple example of such class would be:
class A {
int *a;
public:
A(int value) {
this->a = new int;
*(this->a) = value;
}
~A() {
delete this->a;
}
int getValue() const { return this->a; }
}
I want to use the class and pass it by value to other functions, etc. At least these examples must work without creating memory leaks or double free errors.
A f1() {
// some function that returns A
A value(5);
// ...
return value;
}
void f2(A a) {
// takes A as a parameter
// ...
}
A a = f1();
A b = a;
f2(a);
f2(f1());
The class A is incomplete because I should override operator= and A(A& oldValue) to solve some of these problems.
As I understand it, the default implementation of these methods just copy the value of the members which is causing the destructor to be called twice on the same pointer values.
Am I right and what else am I missing?
In addition, do you know any good tutorial that explains this issue?
Use containers and smart pointers.
E.g. std::vector for dynamic length array, or boost::shared_ptr for dynamically allocated single object.
Don't deal directly with object lifetime management.
Cheers & hth.,
When you pass an object like that, you will create a copy of the object. To avoid doing that, you should pass a const reference...
void f2(A const & a)
{
}
This does mean that you are not allowed to change 'a' in your function - but, to be honest, you shouldn't be doing that anyways, as any changes won't be reflected back to the original parameter that was passed in. So, here the compiler is helping you out, but not compiling when you would have made a hard to find error.
Specifically, you must implement a copy constructor that properly copies the memory pointer for the a variable. Any default constructor would simply copy the memory location for the a variable, which would obviously be subject to a double-delete.
Even doing this:
A value(5);
// ...
return value;
won't work because when A falls out of scope (at the end of the section) the delete operator for A will be called, thus deleting the a sub-variable and making the memory invalid.
I need to store a list of various properties of an object. Property consists of a name and data, which can be of any datatype.
I know I can make a class "Property", and extend it with different PropertySubClasses which only differ with the datatype they are storing, but it does not feel right.
class Property
{
Property(std::string name);
virtual ~Property();
std::string m_name;
};
class PropertyBoolean : Property
{
PropertyBoolean(std::string name, bool data);
bool m_data;
};
class PropertyFloat : Property
{
PropertyFloat(std::string name, float data);
float m_data;
};
class PropertyVector : Property
{
PropertyVector(std::string name, std::vector<float> data);
std::vector<float> m_data;
};
Now I can store all kinds of properties in a
std::vector<Property*>
and to get the data, I can cast the object to the subclass. Or I can make a pure virtual function to do something with the data inside the function without the need of casting.
Anyways, this does not feel right to create these different kind of subclasses which only differ by the data type they are storing. Is there any other convenient way to achieve similar behavior?
I do not have access to Boost.
C++ is a multi-paradigm language. It shines brightest and is most powerful where paradigms are mixed.
class Property
{
public:
Property(const std::string& name) //note: we don't lightly copy strings in C++
: m_name(name) {}
virtual ~Property() {}
private:
std::string m_name;
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const std::string& name, const T& data)
: Property(name), m_data(data);
private:
T m_data;
};
typedef std::vector< std::shared_ptr<Property> > property_list_type;
Edit: Why using std::shared_ptr<Property> instead of Property*?
Consider this code:
void f()
{
std::vector<Property*> my_property_list;
for(unsigned int u=0; u<10; ++u)
my_property_list.push_back(new Property(u));
use_property_list(my_property_list);
for(std::vector<Property*>::iterator it=my_property_list.begin();
it!=my_property_list.end(); ++it)
delete *it;
}
That for loop there attempts to cleanup, deleting all the properties in the vector, just before it goes out of scope and takes all the pointers with it.
Now, while this might seem fine for a novice, if you're an only mildly experienced C++ developer, that code should raise alarm bells as soon as you look at it.
The problem is that the call to use_property_list() might throw an exception. If so, the function f() will be left right away. In order to properly cleanup, the destructors for all automatic objects created in f() will be called. That is, my_property_list will be properly destroyed. std::vector's destructor will then nicely cleanup the data it holds. However, it holds pointers, and how should std::vector know whether these pointers are the last ones referencing their objects?
Since it doesn't know, it won't delete the objects, it will only destroy the pointers when it destroys its content, leaving you with objects on the heap that you don't have any pointers to anymore. This is what's called a "leak".
In order to avoid that, you would need to catch all exceptions, clean up the properties, and the rethrow the exception. But then, ten years from now, someone has to add a new feature to the 10MLoC application this has grown to, and, being in a hurry, adds code which leaves that function prematurely when some condition holds. The code is tested and it works and doesn't crash - only the server it's part of now leaks a few bytes an hour, making it crash due to being out of memory about once a week. Finding that makes for many hours of fine debugging.
Bottom line: Never manage resources manually, always wrap them in objects of a class designed to handle exactly one instance of such a resource. For dynamically allocated objects, those handles are called "smart pointer", and the most used one is shared_ptr.
A lower-level way is to use a union
class Property
union {
int int_data;
bool bool_data;
std::cstring* string_data;
};
enum { INT_PROP, BOOL_PROP, STRING_PROP } data_type;
// ... more smarts ...
};
Dunno why your other solution doesn't feel right, so I don't know if this way would feel better to you.
EDIT: Some more code to give an example of usage.
Property car = collection_of_properties.head();
if (car.data_type == Property::INT_PROP) {
printf("The integer property is %d\n", car.int_data);
} // etc.
I'd probably put that sort of logic into a method of the class where possible. You'd also have members such as this constructor to keep the data and type field in sync:
Property::Property(bool value) {
bool_data = value;
data_type = BOOL_PROP;
}
I suggest boost::variant or boost::any. [Related question]
Write a template class Property<T> that derives from Property with a data member of type T
Another possible solution is to write a intermediate class managing the pointers to Property classes:
class Bla {
private:
Property* mp
public:
explicit Bla(Property* p) : mp(p) { }
~Bla() { delete p; }
// The standard copy constructor
// and assignment operator
// aren't sufficient in this case:
// They would only copy the
// pointer mp (shallow copy)
Bla(const Bla* b) : mp(b.mp->clone()) { }
Bla& operator = (Bla b) { // copy'n'swap trick
swap(b);
return *this;
}
void swap(Bla& b) {
using std::swap; // #include <algorithm>
swap(mp, b.mp);
}
Property* operator -> () const {
return mp;
}
Property& operator * () const {
return *mp;
}
};
You have to add a virtual clone method to your classes returning a pointer to a newly created copy of itself:
class StringProperty : public Property {
// ...
public:
// ...
virtual Property* clone() { return new StringProperty(*this); }
// ...
};
Then you'll be able to do this:
std::vector<Bla> v;
v.push_back(Bla(new StringProperty("Name", "Jon Doe")));
// ...
std::vector<Bla>::const_iterator i = v.begin();
(*i)->some_virtual_method();
Leaving the scope of v means that all Blas will be destroyed freeing automatically the pointers they're holding. Due to its overloaded dereferencing and indirection operator the class Bla behaves like an ordinary pointer. In the last line *i returns a reference to a Bla object and using -> means the same as if it was a pointer to a Property object.
A possible drawback of this approach is that you always get a heap operation (a new and a delete) if the intermediate objects must be copied around. This happens for example if you exceed the vector's capacity and all intermediate objects must be copied to a new piece of memory.
In the new standard (i.e. c++0x) you'll be able to use the unique_ptr template: It
can be used inside the standard containers (in contrast to the auto_ptr which must not be used in the standard containers),
offers the usually faster move semantics (it can easily passed around) and
takes care over the held pointers (it frees them automatically).
I see that there are lots of shots at trying to solve your problem by now, but I have a feeling that you're looking in the wrong end - why do you actually want to do this in the first place? Is there some interesting functionality in the base class that you have omitted to specify?
The fact that you'd be forced to switch on a property type id to do what you want with a specific instance is a code smell, especially when the subclasses have absolutely nothing in common via the base class other than a name (which is the type id in this case).
Starting with C++ 17 we have something called as std::variant and std::any.
std::variant
An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value.
std::any
The class any describes a type-safe container for single values of any copy constructible type.
An object of class any stores an instance of any type that satisfies the constructor requirements or is empty, and this is referred to as the state of the class any object. The stored instance is called the contained object. Two states are equivalent if they are either both empty or if both are not empty and if the contained objects are equivalent.
The non-member any_cast functions provide type-safe access to the contained object.
You can probably do this with the Boost library, or you could create a class with a type code and a void pointer to the data, but it would mean giving up some of the type safety of C++. In other words, if you have a property "foo", whose value is an integer, and give it a string value instead, the compiler will not find the error for you.
I would recommend revisiting your design, and re-evaluating whether or not you really need so much flexibility. Do you really need to be able to handle properties of any type? If you can narrow it down to just a few types, you may be able to come up with a solution using inheritance or templates, without having to "fight the language".
Per-frame I need to allocate some data that needs to stick around until the end of the frame.
Currently, I'm allocating the data off a different memory pool that allows me to mark it with the frame count. At the end of the frame, I walk the memory pool and delete the memory that was allocated in a particular frame.
The problem I'm running into is that in order to keep a hold on the data, I have to place it in a structure thusly:
struct FrameMemory
{
uint32 frameIndex;
bool allocatedType; //0 = new(), 1 = new[]
void* pMemPtr;
}
So later, when i get around to freeing the memory, it looks something like this:
{
for(all blocks)
if(block[i].frameIndex == targetIndex)
if(block[i].allocatedType == 0)
delete block[i].pMemPtr;
else if (block[i].allocatedType ==1)
delete[] block[i].pMemPtr;
}
The issue is that, because I have to overload the pointer to the memory as a void*, the DELETE operator doesn't properly DELETE the memory as its' native base type. IE the destructor NEVER gets called for the object.
I've attempted to find ways to use smart-pointer templated objects for the solution, but in order to do that, I have to overload the templated class to a non-templated base-type, which makes deletion even more difficult.
Does anyone have a solution to a problem like this?
If you don't want to force all the objects to inherit from Destructible, you can store a pointer to a deleter function (or functor) along with the pointer to the data itself. The client code is responsible for providing a function that knows how to delete the data correctly, typically something like:
void xxx_deleter(void *data) {
xxx *ptr = static_cast<xxx *>(data);
delete ptr;
}
Though the deleter will usually be a lot like the above, this also gives the client the option of storing complex data structures and still getting them deleted correctly.
class Destructable
{
public:
virtual ~Destructable() {}
};
Instead of void *, store Destructable * in the pool. Make objects allocated from the pool inherit from Destructable.
Alternatively, override the operators new and delete for the relevant classes. Make them use the pool. Delete the object as soon as the CPU is done with it, in the regular way, in the code that owns it and hence knows its correct type; since the pool will not reuse the memory until it sees the appropriate frame end, whatever asynchronous hardware required you to lag garbage collection in this way can still do its thing.
The only way I could think of to do that would be to add a type entry to the FrameMemory struct, then use that to properly cast the memory for the delete. For example, if you have memory of type foo, you could have something like:
if (block[i].BlockType == BLOCKTYPE_FOO)
{
foo *theMemory = (foo *)block[i].pMemPtr;
delete theMemory;
}
Note that this can be an ****extremely**** dangerous operation if you do it wrong.
If you are mean stack frame (i.e. inside function)
you can try to use alloca()
First thing that I can think of is using boost::shared_ptr<void> (for the non-array version, some work may be required to adapt it for the array version) as the pointer type. And I think that should take care of mostly every detail. Whenever the frame is destroyed the memory will be appropriately deleted:
struct FrameMemory
{
uint32 frameIndex;
// bool allocatedType; //0 = new(), 1 = new[] only works with instances, not arrays
boost::shared_ptr<void> pMemPtr;
};
If you want to implement something similar manually, you can use a 'deleter' function pointer to handle the deletion of the objects, instead of calling delete directly. Here is a rough approach to how you could modify your code:
// helper deleter functions
template <typename T>
void object_deleter( void *p ) {
delete static_cast<T*>(p);
}
template <typename T>
void array_deleter( void *p ) {
delete [] static_cast<T*>(p);
}
class FrameMemory
{
public:
const uint32 frameIndex;
void* pMemPtr;
private:
void (*deleter)(void*);
public:
template <typename T>
FrameMemory( uint32 frame, T* memory, bool isarray = false )
: frameIndex(frame), pMemPtr(memory),
deleter( isarray? array_deleter<T> : object_deleter<T> )
{}
void delete() {
deleter(pMemPtr)
}
};
struct X;
void usage()
{
{
FrameMemory f( 1, new X );
f.delete();
}
{
FrameMemory f( 1, new x[10], true );
f.delete();
}
}
I would modify it further so that instead of having to call FrameMemory::delete() that was performed in the destructor, but that would take more time than I have right now to do correctly (that is, deciding how copies are to be handled and so on...
I would do something like this:
struct FrameMemoryBase
{
uint32 frameIndex;
bool allocatedType; //0 = new(), 1 = new[]
virtual void Free() = 0;
};
template <typename T>
struct FrameMemory : public FrameMemoryBase
{
void Free()
{
if(allocatedType == 0)
delete pMemPtr;
else if (allocatedType ==1)
delete[] pMemPtr;
}
T *pMemPtr;
};
which you would use via:
{
for(all blocks)
if(block[i].frameIndex == targetIndex)
block[i].Free();
}
If you also free the FrameMemory struct you could just change Free to a virtual destructor. I'm not sure this is what you're looking for since I don't understand what "I've attempted to find ways to use smart-pointer templated objects for the solution, but in order to do that, I have to overload the templated class to a non-templated base-type, which makes deletion even more difficult." means, but I hope this is helpful.
This requires that the memory management code somehow have access to the declarations of what you wish to free, but I don't think there's any way around that, assuming you want destructors called, which you explicitly do.