I am working on a library that support multiple programming environment such as VB6 and FoxPro. I have to stick with C convention as it is the lowest common denominator. Now I have a question regarding the style.
Suppose that the function process input and returns a string. During the process, the error can happen. The current proposed style is this:
int func(input params... char* buffer, unsigned int* buffer_size);
The good thing about this style is that everything is included in the prototype, including error code. And memory allocation can be avoided. The problem is that the function is quite verbose. And because the buffer_size can be any, it requires more code to implement.
Another option is to return char*, and return NULL to indicate error:
char* func(input params...);
This style requires caller to delete the buffer. Memory allocation is required so a server program could face memory fragmentation issue.
A variant of the second option is to use a thread local variable to hold the returned pointer char*, so that the user does not need to delete the buffer.
Which style do you like? And reason?
I'm a bit "damaged goods" when it comes to this subject. I used to design and maintain fairly large APIs for embedded telecom. A context where you cannot take anything for granted. Not even things like global variables or TLS. Sometimes even heap buffers show up that actually are addressed ROM memory.
Hence, if you're looking for a "lowest common denominator", you might also want to think about what language constructs are available in your target environment (the compiler is likely to accept anything within standard C, but if something is unsupported the linker will say no).
Having said that, I would always go for alternative 1. Partly because (as others have pointed out), you should never allocate memory for the user directly (an indirect approach is explained further down). Even if the user is guaranteed to work with pure and plain C, they still might for instance use their own customized memory management API for tracking leaks, diagnostic logging etc. Support for strategies like that is commonly appreciated.
Error communication is one of the most important things when dealing with an API. Since the user probably have distinct ways to handle errors in his code, you should be as consistent as possible about this communication throughout the API. The user should be able to wrap error handling towards your API in a consistent way and with minimum code. I would generally always recommend using clear enum codes or defines/typedefs. I personally prefer typedef:ed enums:
typedef enum {
RESULT_ONE,
RESULT_TWO
} RESULT;
..because it provides type/assignment safety.
Having a get-last-error function is also nice (requires central storage however), I personally use it solely for providing extra information about an already recognized error.
The verbosity of alternative 1 can be limited by making simple compounds like this:
struct Buffer
{
unsigned long size;
char* data;
};
Then your api might look better:
ERROR_CODE func( params... , Buffer* outBuffer );
This strategy also opens up for more elaborate mechanisms. Say for instance you MUST be able to allocate memory for the user (e.g. if you need to resize the buffer), then you can provide an indirect approach to this:
struct Buffer
{
unsigned long size;
char* data;
void* (*allocator_callback)( unsigned long size );
void (*free_callback)( void* p );
};
Ofcourse, the style of such constructs is always open for serious debate.
Good Luck!
I would prefer the first definition, where buffer and its size are passed in. There are exceptions, but usually you don't expect to have to clean up after the functions you call. Whereas if I allocate memory and pass it into a function, then I know that I have to clean up after myself.
Handling different sized buffers shouldn't be a big deal.
Another issue with the second style is that the contexts that the memory is allocated on may be different. For example:
// your library in C
char * foo() {
return malloc( 100 );
}
// my client code C++
char * p = foo(); // call your code
delete p; // natural for me to do, but ... aaargh!
And this is only a minor part of the problem. You can say that both sides should use malloc & free, but what if they are using diffeent compiler implementations? It is better for all allocations and deallocations to occur in the same place. whether this is the library r the client code is up to you.
If I have to choose between the two styles shown I'd go for the 1st one every time. The 2nd style gives the users of your library something else to think about, memeory allocation, and someone is bound to forget to free the memory.
The second variant is cleaner.
COM IErrorInfo is an implementation of the second approach. The server calls SetErrorInfo to set details of what went wrong and returns an error code. The caller examines the code and can call GetErrorInfo to get the details. The caller is responsible for releasing the IErrorInfo, but passing the parameters of each call in the first variant is not beautiful either.
The server could preallocate enough memory on start so that it surely has enough memory to return error details.
Few things to ponder;
Allocation and deallocation should happen at the same scope (ideally). It is best to pass in an pre-allocated buffer by the caller. The caller can safely free this later on. This poses the question -- how big the buffer should be? An approach that I've seen used fairly widely in Win32 is to pass NULL as the input buffer and the size parameter will tell you how much you need.
How many possible error conditions do you oversee? Returning a char* may limit the extent of error reporting.
What pre and post conditions do you want to be fulfilled? Does your prototype reflect that?
Do you do error checking in the caller or the callee?
I can't really tell you one is better than the other, since I don't have the big picture. But I am sure these things can get your started thinking as well as the other posts.
What about using both methods? I agree with the consensus of answers favoring style 1 vs. the pitfalls of style 2. I do feel style 2 could be used if all your API's follow a consistent naming idiom, like so:
// Style 1 functions
int fooBuff(char* buffer, unsigned int buffer_size, input params... );
// Style 2 functions
char* fooBuffAlloc(input params...);
bool fooBuffFree(char* foo);
/D
The first edition would be less error prone when other programmers use it.
If programmers have to allocate memory themselves they are more likely to remember to free it. If a library allocates memory for them it's yet another abstraction and can/will lead to complications.
I'd do it similarly to the first way, but just subtly different, after the model of snprintf and similar functions:
int func(char* buffer, size_t buffer_size, input params...);
This way, if you have lots of these, they can look similar, and you can use variable numbers of arguments wherever useful.
I agree greatly with the already-stated reasons for using version 1 rather than version 2 - memory problems are much more likely with version 2.
Related
I hope this question is not too subjective.. all I want is good design that would prevent memory leaks happening later in my code. I coulnd't find any question on SO. I always found questions about what to do after allocating data in function which is not my case.
Also for some reason I am not using newer C++ standards like C++11 (shared pointers).
Let me demonstrate by example:
I have logic of data buffering which are later being sent. The buffering is done in one class and sending in another class.
In one point of code I am taking some data from buffer, process it (check the type of data etc) and then send it with function send:
bool send_data(char *data, size_t data_length) {
The data are consumed and are no longer needed. Shall I free them in the send_data or shell I leave that to the caller?
Free it inside:
bool send_data(char *data, size_t data_length) {
//... process data ...
send(data, data_length, ...);
delete[] data;
}
Leave it and let the caller free it:
send_data(data,data_length);
delete[] data;
Or is there a design flaw and I should do something totally different?
The reason for not using C++11 is that the code is big & old - should I rewrite it completely? But I am considering to rewrite just some parts of the code because something is better then nothing.
And also the usage of some pointers spans lots of places of code I would have to change them all. Sometimes its not so easy to find them all because the usage may be hidden by casting and the buffering etc.
The data buffering is important. I have lot of data in buffers not just one char array. I am not sure if the data can be made static as some of you have in answers.. I will think about it.
If you don't want to use c++11, you can use std::auto_ptr, or if you can actually, use std::unique_ptr.
But as I see, it seems like you are using char * for, may be, an array. If so, don't use smart pointers (at least without custom deallocators) and call delete[] instead of delete.
Also, if you need to pass a char *, you can use
std::vector<char> vec;
vec.push_back(...);
//...
send_data(&vec[0], vec.size());
If you are sure you strongly want to use char *, delete it in the caller, it is far better practice. Because who allocates memory is it's owner, so owner deletes it. Also it removes a side effect from callee, and makes it callee easier to use for other developers, who won't expect i.e that send_data will also delete their data.
If you want good design to prevent memory leaks, the answer is to use a container, and there are plenty of containers to chose from that don't require C++11. If you want it to be as "freeform raw data" as possible, then yes, you should use a newer standard and use unique or shared pointers - is there any particular reason you're still stuck in the last decade compiler-wise?
If you want to handle it the C way (which is what you're insisting on doing above), then it's really application dependent. If you meet the following constraints:
1) Only one thread will use the data at a time
2) The data size is never prohibitive
3) There's nothing else that would make it unreasonable to leave it sticking around
... then I recommend storing it in a static pointer, wherein nobody ever needs to free it. That's what a lot of the stdlib library functions do when they deal with strings.
C++ style would be to use the safe ptr wrappers.
C style, as here, means definitely leave it to the caller.
The call could be:
char data[256];
...
send(data, sizeof(data);
So no delete[] data
To be a bit more safe, you could hide the original send and manage data and its deletion separately. C++ as class, C style as a couple of functions.
struct Data {
char* data;
size_t size;
};
void send(struct Data* data) {
if (!data->data) {
throw new IllegalStateException("...");
}
_send(data->data, data->size);
delete[] data->data;
data->data = NULL;
}
Note: when I say "static string" here I mean memory that can not be handled by realloc.
Hi, I have written a procedure that takes a char * argument and I would like to create a duplicate IF the memory is not relocatable/resizable via realloc. As is, the procedure is a 'heavy' string processor, so being ignorant and duplicating the string whether or not it is static will surely cause some memory overhead/processing issues in the future.
I have tried to use exception handlers to modify a static string, the application just exits without any notice. I step back, look at C and say: "I'm not impressed." That would be an exception if I have ever heard of one.
I tried to use exception handlers to call realloc on a static variable... Glib reports that it can't find some private information to a structure (I'm sure) I don't know about and obviously calls abort on the program which means its not an exception that can be caught with longjmp/setjmp OR C++ try, catch finally.
I'm pretty sure there must be a way to do this reasonably. For instance dynamic memory most likely is not located anywhere near the static memory so if there is a way to divulge this information from the address... we might just have a bingo..
I'm not sure if there are any macros in the C/C++ Preprocessors that can identify the source and type of a macro argument, but it would be pretty dumb if it didn't. Macro Assemblers are pretty smart about things like that. Judging by the lack of robust error handling, I would not be a bit surprised if it did not.
C does not provide a portable way to tell statically allocated memory blocks from dynamically allocated ones. You can build your own struct with a string pointer and a flag indicating the type of memory occupied by the object. In C++ you can make it a class with two different constructors, one per memory type, to make your life easier.
As far as aborting your program goes, trying to free or re-allocate memory that has not been allocated dynamically is undefined behavior, so aborting is a fair game.
You may be able to detect ranges of memory and do some pointer comparisons. I've done this in some garbage collection code, where I need to know whether a pointer is in the stack, heap, or elsewhere.
If you control all allocation, you can simply keep min and max bounds based on every dynamic pointer that ever came out of malloc, calloc or realloc. A pointer lower than min or greater than max is probably not in the heap, and this min and max delimited region is unlikely to intersect with any static area, ever. If you know that a pointer is either static or it came from malloc, and that pointer is outside of the "bounding box" of malloced storage, then it must be static.
There are some "museum" machines where that sort of stuff doesn't work and the C standard doesn't give a meaning to comparisons of pointers to different objects using the relational operators, other than exact equality or inequality.
Any solution you would get would be platform specific, so you might want to specify the platform you are running on.
As for why a library should call abort when you pass it unexpected parameters, that tends to be safer than continuing execution. It's more annoying, certainly, but at that point the library knows that the code calling into it is in an state that cannot be recovered from.
I have written a procedure that takes a char * argument and I would like to create a duplicate IF the memory is not relocatable/resizable via realloc.
Fundamentally, the problem is that you want to do memory management based on information that isn't available in the scope you're operating in. Obviously you know if the string is on the stack or heap when you create it, but that information is lost by the time you're inside your function. Trying to fix that is going to be nearly impossible and definitely outside of the Standard.
I have tried to use exception handlers to modify a static string, the application just exits without any notice. I step back, look at C and say: "I'm not impressed." That would be an exception if I have ever heard of one.
As already mentioned, C doesn't have exceptions. C++ could do this, but the C++ Standards Committee believes that having C functions behave differently in C++ would be a nightmare.
I'm pretty sure there must be a way to do this reasonably.
You could have your application replace the default stack with one you created (and, as such, know the range of addresses in) using ucontext.h or Windows Fibers, and check if the address is inside the that range. However, (1) this puts a huge burden on any application using your library (of course, if you wrote the only application using your library, then you may be willing to accept that burden); and (2) doesn't detect memory that can't be realloced for other reasons (allocated using static, allocated using a custom allocator, allocated using SysAlloc or HeapAlloc on Windows, allocated using new in C++, etc.).
Instead, I would recommend having your function take a function pointer that would point at a function used to reallocate the memory. If the function pointer is NULL, then you duplicate the memory. Otherwise, you call the function.
original poster here. I neglected to mention that I have a working solution to the problem, it is not as robust as I would have hoped for. Please do not be upset, I appreciate everyone participating in this Request For Comments and Answers. The 'procedure' in question is variadic in nature and expects no more than 63 anonymous char * arguments.
What it is: a multiple string concatenator. It can handle many arguments but I advise the developer against passing more than 20 or so. The developer never calls the procedure directly. Instead a macro known as 'the procedure name' passes the arguments along with a trailing null pointer, so I know when I have met the end of statistics gathering.
If the function recieves only two arguments, I create a copy of the first argument and return that pointer. This is the string literal case. But really all it is doing is masking strdup
Failing the single valid argument test, we proceed to realloc and memcpy, using record info from a static database of 64 records containing each pointer and its strlen, each time adding the size of the memcopy to a secondary pointer (memcpy destination) that began as a copy of the return value from realloc.
I've written a second macro with an appendage of 'd' to indicate that the first argument is not dynamic, therefore a dynamic argument is required, and that macro uses the following code to inject a dynamic argument into the actual procedure call as the first argument:
strdup("")
It is a valid memory block that can be reallocated. Its strlen returns 0 so when the loop adds the size of it to the records, it affects nothing. The null terminator will be overwritten by memcpy. It works pretty damned well I should say. However being new to C in only the past few weeks, I didn't understand that you can't 'fool proof' this stuff. People follow directions or wind up in DLL hell I suppose.
The code works great without all of these extra shenanigans do-hickies and whistles, but without a way to reciprocate a single block of memory, the procedure is lost on loop processing, because of all the dynamic pointer mgmt. involved. Therefore the first argument must always be dynamic. I read somehwere someone had suggested using a c-static variable holding the pointer in the function, but then you can't use the procedure to do other things in other functions, such as would be needed in a recursive descent parser that decided to compile strings as it went along.
If you would like to see the code just ask!
Happy Coding!
mkstr.cpp
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
struct mkstr_record {
size_t size;
void *location;
};
// use the mkstr macro (in mkstr.h) to call this procedure.
// The first argument to mkstr MUST BE dynamically allocated. i.e.: by malloc(),
// or strdup(), unless that argument is the sole argument to mkstr. Calling mkstr()
// with a single argument is functionally equivalent to calling strdup() on the same
// address.
char *mkstr_(char *source, ...) {
va_list args;
size_t length = 0, item = 0;
mkstr_record list[64]; /*
maximum of 64 input vectors. this goes beyond reason!
the result of this procedure is a string that CAN be
concatenated by THIS procedure, or further more reallocated!
We could probably count the arguments and initialize properly,
but this function shouldn't be used to concatenate more than 20
vectors per call. Unless you are just "asking for it".
In any case, develop a workaround. Thank yourself later.
*/// Argument Range Will Not Be Validated. Caller Beware!!!
va_start(args, source);
char *thisArg = source;
while (thisArg) {
// don't validate list bounds here.
// an if statement here is too costly for
// for the meager benefit it can provide.
length += list[item].size = strlen(thisArg);
list[item].location = thisArg;
thisArg = va_arg(args, char *);
item++;
}
va_end(args);
if (item == 1) return strdup(source); // single argument: fail-safe
length++; // final zero terminator index.
char *str = (char *) realloc(source, length);
if (!str) return str; // don't care. memory error. check your work.
thisArg = (str + list[0].size);
size_t count = item;
for (item = 1; item < count; item++) {
memcpy(thisArg, list[item].location, list[item].size);
thisArg += list[item].size;
}
*(thisArg) = '\0'; // terminate the string.
return str;
}
mkstr.h
#ifndef MKSTR_H_
#define MKSTR_H_
extern char *mkstr_(char *string, ...);
// This macro ensures that the final argument to "mkstr" is null.
// arguments: const char *, ...
// limitation: 63 variable arguments max.
// stipulation: caller must free returned pointer.
#define mkstr(str, args...) mkstr_(str, ##args, NULL)
#define mkstrd(str, args...) mkstr_(strdup(str), ##args, NULL)
/* calling mkstr with more than 64 arguments should produce a segmentation fault
* this is not a bug. it is intentional operation. The price of saving an in loop
* error check comes at the cost of writing code that looks good and works great.
*
* If you need a babysitter, find a new function [period]
*/
#endif /* MKSTR_H_ */
Don't for get to mention me in the credits. She's fine and dandy.
Would it be possible in C++ to create a custom allocator that works simply like this:
{
// Limit memory to 1024 KB
ScopedMemoryPool memoryPool(1024 * 1024);
// From here on all heap allocations ('new', 'malloc', ...) take memory from the pool.
// If the pool is depleted these calls result in an exception being thrown.
// Examples:
std::vector<int> integers(10);
int a * = new int [10];
}
I couldn't find something like this in the boost libraries, or anywhere else.
Is there a fundamental problem that makes this impossible?
You would need to create a custom allocator that you pass in as a template param to vector. This custom allocator would essentially wrap the access to your pool and do whatever size validations that it wants.
Yes you can make such a construct, it's used in many games, but you'll basically need to implement your own containers and call memory allocation methods of that pool that you've created.
You could also experiment with writing a custom allocator for the STL containers, although it seems that that sort of work is generally advised against. (I've done it before and it was tedious, but I don't remember any specific problems.)
Mind- writing your own memory allocator is not for the faint of heart. You could take a look at Doug Lea's malloc, which provides "memory spaces", which you could use in your scoping construct somehow.
I will answer a different question. Look at 'efficient c++' book. One of the things they discuss is implementing this kind of thing. That was for a web server
For this particular thing you can either mess at the c++ layer by overriding new and supplying custom allocators to the STL.
Or you can mess at the malloc level, start with a custom malloc and work from there (like dmalloc)
Is there a fundamental problem that makes this impossible?
Arguing about program behavior would become fundamentally impossible. All sorts of weird issues will come up. Certain sections of the code may or may not execute though this will seeminly have no effect on the next sections which may work un-hindered. Certain sections may always fail. Dealing with the standard-library or any other third party library will become extremely difficult. There may be fragmentations at run-time at times and at times not.
If intent is that all allocations within that scope occur with that allocator object, then it's essentially a thread-local variable.
So, there will be multithreading issues if you use a static or global variable to implement it. Otherwise, not a bad workaround for the statelessness of allocators.
(Of course, you'll need to pass a second template argument eg vector< int, UseScopedPool >.)
I am working on a group senior project for my university and I have run into a major hurdle in trying to get my code to work.
The compiler that we have for our 8 bit Atmel microcontroller does not support the new or delete operators, and it does not support the C++ STL. I could program it in C, but I have to implement an A* algorithm which I have never done before. While I have tried C initially I soon realized that I never did pure C before. Trying to model objects with structs and functions is slowing me down since I am so used to the much cleaner C++ syntax.
Regardless, the exact wording for my compilers shortcomings can be found here: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus
To overcome them and still use C++ I have considered the following possibilities.
1) Don't allocate anything, just use templates to generate fixed arrays on the stack.
2) Allocate and find some hack to call the constructor for objects once I have allocated the space for them. Placement new isn't an option since new isn't an operator.
3) Just use C and suck it up, its a microcontroller why am I getting fancy?
4) Find a better compiler which will probably cost $$$.
The second option is the hardest but it would have the biggest pay off in terms of how I can write this code. However, I imagine that debugging it could be a huge pain if I get it wrong. I'm thinking of creating objects on the stack, copying their bits into the allocated space, and then zeroing the bits in the object so it doesn't call its destructor. To do that I would access the bits directly with an unsigned char pointer and the sizeof operator to get the byte count.
That sounds terrible and I don't know if it could work reliably, but I am considering it. I know vtables can be a problem but I don't intend on having any vtables since it is just an 8 bit microcontroller.
Don't fight your tools. If the only compiler you have for your embedded system is a C compiler, learn C - it's not difficult. Trying to produce some bastardised version of the two languages just to solve a fairly simple programming problem will only
end in tears.
To look at it another way, if your embedded platform didn't even support a C compiler, but only an assembler, would your first impulse be to sit down and write a C++ compiler in assembler? I hope not, I hope you would instead sit down and learn to use
the assembler to complete your assignment - writing a C++ compiler (or even a C compiler) would be totally inappropriate use of your time, and would almost certainly result in failure.
Just for the record, zeroing the bits in an object won't affect whether the destructor gets called (unless the compiler has a special quirk that enables this behaviour). Just write some logging statements in your destructor to test this out.
Structuring your program not to allocate anything is probably the way the system was designed. I've not worked with embedded systems before, however I have read some experienced embedded shops that discourage use of dynamic memory because the runtime environment has scarce amounts of it.
However, if you must, you can still use placement new. If you don't have the <new> header, here are the relevant lines directly from it on my version of GCC:
// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) throw() { return __p; }
inline void* operator new[](std::size_t, void* __p) throw() { return __p; }
// Default placement versions of operator delete.
inline void operator delete (void*, void*) throw() { }
inline void operator delete[](void*, void*) throw() { }
Stick that somewhere in a header file included by every source file that uses placement new/delete.
Sample file that tests this:
#include <cstdio>
#include <new>
int
main(int argc, char** argv)
{
typedef char const* cstr;
char foobar[16];
cstr* str = new (&foobar) cstr(argc > 1 ? argv[1] : "Hello, world!");
std::puts(*str);
str->~cstr();
}
On my version of GCC, this does not use libstdc++ at all (if -fno-exceptions is used).
Now, if you want to combine that with malloc (if your platform provides this), then you can do this:
#include <cstdio>
#include <cstdlib>
inline void* operator new (std::size_t n) {return std::malloc(n);}
inline void* operator new[](std::size_t n) {return std::malloc(n);}
inline void operator delete (void* p) {std::free(p);}
inline void operator delete[](void* p) {std::free(p);}
int
main(int argc, char** argv)
{
typedef char const* cstr;
cstr* str = new cstr(argc > 1 ? argv[1] : "Hello, world!");
std::puts(*str);
delete str;
}
This allows you to use the standard new/delete that you're familiar with, without requiring use of libstdc++.
Good luck!
I think you are approaching the problem from a viewpoint that is less than optimum.
You are focusing on the compiler (or lack thereof) instead of focusing on the HARDWARE.
The most probable answer to your main questions is "because the hardware doesn't support all that C++ stuff". Embedded hardware (microcontrolers) are noted for the customization of the hardware design - memory maps, interrupt handlers, I/O, etc.
In my opinion, you should FIRST spend some time with the hardware book for the microcontroller, learning the ins and outs of the device - i.e. how it was designed and for what primary purpose. Some were designed for fast memory manipulation, some for fast I/O handling, some for A/D type work, some for signal processing. The type of microcontroller dictates the assembler instructions they wrote for it, and that dictates what any higher-level compiler can do efficiently.
If this is important, spend some time to look at the assembler as well - it will tell you what the designers considered important. It will also tell you a lot about how much you can get from a high-level compiler.
Generally, microcontrollers don't support C++ because the design really doesn't care about objects, or fancy memory handling (from the C++ perspective). It can be done, but you are often trying to pound a round peg in a square hole to get constructors and destructors (and 'new' and 'delete') to work in the micro environment.
IF you have a C compiler for this unit, consider it a blessing. A good C compiler is often "more than enough" to create excellent embedded software.
Cheers,
-Richard
Just because it doesn't have these tools doesn't mean you can't benefit from C++. If the project is large enough, access to Object Oriented design alone could be motivation enough.
If it doesn't support 'new' then it's probably because it doesn't make sense to make an automatic distinction between a heap and the stack. This might be because of your memory configuration. It might also be because memory resources are so constrained only very careful allocation makes sense. If you absolutely have to implement your own 'new' operator, you might look into adapting Doug Lea's malloc. I believe he began his allocator in a similar circumstance (reimplementing C++'s new).
I love the STL but it's still possible to do useful stuff without it. Depending on the scope of the project you might be better off just using an array.
I had a similar compiler that implemented a bizarre version of the Embedded-C++ standard. We had operator new which would call constructors for us and destructors were called in most cases. The compiler/runtime vendor went and implemented try and catch using setjmp and longjmp as a convenience to the engineer. The problem was that they never mentioned that a throw would not cause destructors of local objects to be invoked!
Anyway, our group inherited the code base after someone wrote an application acting like it was Standard C++: using RAII techniques and all of the other goodness. We ended up rewriting it in what a number of us call object-oriented C instead. You might want to consider just biting the bullet and writing in straight C. Instead of constructors, have an explicitly called initialization method. Destructors become an explicitly called termination method. There isn't much of C++ that you can't mimic in C pretty quickly. Yes, MI is a pain in the ... but single inheritance is pretty easy. Take a look at this PDF for some ideas. It almost describes the approach that we took. I really wish I had written our method down somewhere...
You may find some helpful code on my A* tutorial website. Although the code I wrote to support this uses STL in should be easy to strip the STL support out. In addition there is a pool allocator included with it (fsa.h) that I wrote to speed up STL on game consoles. It is C++ code, but I ported it originally from C and I don't think it would be hard to do it the other way. The code is tested by over 10,000 people so it's a good base to start from.
Replacing the STL structures I'm using is no problem since it is limited to Vectors. I use one of the vectors as a priority queue using the heap functions (make_heap and push_heap). You can replace that with my old C code which has a priority queue implemented in C that should just drop into your code. (Which only does one alloc, so you can replace that with a pointer to a reserved area of your memory.
As you can see in this code fragment from the header, the main difference in C code is that there's no this pointer, no object, so your code typically takes an object pointer as the first argument.
void PQueueInitialise( PQUEUE *pq, int32 MaxElements, uint32 MaxRating, bool32 bIsAscending );
void PQueueFree( PQUEUE *pq );
int8 PQueuePush( PQUEUE *pq, void *item, uint32 (*PGetRating) ( void * ) );
int32 PQueueIsFull( PQUEUE *pq );
int32 PQueueIsEmpty( PQUEUE *pq );
void *PQueuePop( PQUEUE *pq, uint32 (*PGetRating) ( void * ) );
Why not write it first on your desktop computer, taking into consideration the limitations of the compiler, debug it, make sure it works perfectly and only then move to the embedded environment?
when doing embedded work, I once couldn't even link the C runtime for memory constraints, but the hardware had a DMA (dynamic memory allocator) instruction so I wrote my own malloc with that hardware, your hardware likely has a similar feature, so you could write a malloc and then a new based on the malloc.
Anyways in the end I used 99% stack allocations, and a few limits sets os static objects that I would recycle, by builiding in place. This might me a good solution.
This may not be possible, but I figured I'd ask...
Is there any way anyone can think of to track whether or not an automatic variable has been deleted without modifying the class of the variable itself? For example, consider this code:
const char* pStringBuffer;
{
std::string sString( "foo" );
pStringBuffer = sString.c_str();
}
Obviously, after the block, pStringBuffer is a dangling pointer which may or may not be valid. What I would like is a way to have a wrapper class which contains pStringBuffer (with a casting operator for const char*), but asserts that the variable it's referencing is still valid. By changing the type of the referenced variable I can certainly do it (boost shared_ptr/weak_ptr, for example), but I would like to be able to do it without imposing restrictions on the referenced type.
Some thoughts:
I'll probably need to change the assignment syntax to include the referenced variable (which is fine)
I might be able to look at the stack pointer to detect if my wrapper class was allocated "later" than the referenced class, but this seems hacky and not standard (C++ doesn't define stack behavior). It could work, though.
Thoughts / brilliant solutions?
In general, it's simply not possible from within C++ as pointers are too 'raw'. Also, looking to see if you were allocated later than the referenced class wouldn't work, because if you change the string, then the c_str pointer may well change.
In this particular case, you could check to see if the string is still returning the same value for c_str. If it is, you are probably still valid and if it isn't then you have an invalid pointer.
As a debugging tool, I would advise using an advanced memory tracking system, like valgrind (available only for linux I'm afraid. Similar programs exist for windows but I believe they all cost money. This program is the only reason I have linux installed on my mac). At the cost of much slower execution of your program, valgrind detects if you ever read from an invalid pointer. While it isn't perfect, I've found it detects many bugs, in particular ones of this type.
One technique you may find useful is to replace the new/delete operators with your own implementations which mark the memory pages used (allocated by your operator new) as non-accessible when released (deallocated by your operator delete). You will need to ensure that the memory pages are never re-used however so there will be limitations regarding run-time length due to memory exhaustion.
If your application accesses memory pages once they've been deallocated, as in your example above, the OS will trap the attempted access and raise an error. It's not exactly tracking per se as the application will be halted immediately but it does provide feedback :-)
This technique is applicable in narrow scenarios and won't catch all types of memory abuses but it can be useful. Hope that helps.
You could make a wrapper class that works in the simple case you mentioned. Maybe something like this:
X<const char*> pStringBuffer;
{
std::string sString( "foo" );
Trick trick(pStringBuffer).set(sString.c_str());
} // trick goes out of scope; its destructor marks pStringBuffer as invalid
But it doesn't help more complex cases:
X<const char*> pStringBuffer;
{
std::string sString( "foo" );
{
Trick trick(pStringBuffer).set(sString.c_str());
} // trick goes out of scope; its destructor marks pStringBuffer as invalid
}
Here, the invalidation happens too soon.
Mostly you should just write code which is as safe as possible (see: smart pointers), but no safer (see: performance, low-level interfaces), and use tools (valgrind, Purify) to make sure nothing slips through the cracks.
Given "pStringBuffer" is the only part of your example existing after sString goes out of scope, you need some change to it, or a substitute, that will reflect this. One simple mechanism is a kind of scope guard, with scope matching sString, that affects pStringBuffer when it is destroyed. For example, it could set pStringBuffer to NULL.
To do this without changing the class of "the variable" can only be done in so many ways:
Introduce a distinct variable in the same scope as sString (to reduce verbosity, you might consider a macro to generate the two things together). Not nice.
Wrap with a template ala X sString: it's arguable whether this is "modifying the type of the variable"... the alternative perspective is that sString becomes a wrapper around the same variable. It also suffers in that the best you can do is have templated constructor pass arguments to wrapped constructors up to some finite N arguments.
Neither of these help much as they rely on the developer remembering to use them.
A much better approach is to make "const char* pStringBuffer" simply "std::string some_meaningful_name", and assign to it as necessary. Given reference counting, it's not too expensive 99.99% of the time.