GiNaC and malloc()
I'm trying to use the GiNaC library as a drop-in replacement for the native floating point arithmetic between C types. Namely, I have code which #ifdef's between `typedef double dbl' and `typedef GiNaC::ex dbl', but keeps actual arithmetic expressions involving dbl's the same between the different preprocessor paths. The biggest problem I've run into is memory management. I need to allocate arrays of type dbl for caching purposes. Since, when not using GiNaC, the code has to work with a C compiler, I'm constrained to use malloc() for the allocation. If the GiNaC::ex class had an initialization routine that could be called on a block of memory, I would be extremely happy. Because then, I would be able to do something like: GiNaC::ex *expr; expr = malloc(sizeof(GiNaC::ex)); init_ex(expr); /* Or something similar. */ /* ... Use *expr as a properly constructed instance of GiNaC::ex... */ Since nothing that I could find in the library does what I'd like init_ex() to do, I tried different ways of implementing it myself. However, each of the following has prevented me from getting it to work: - GiNaC::ex overloads the = operator, which expectes the lhs to be properly constructed. - the GiNaC::ex constructor stores references to dynamically allocated memory which are freed by the destructor, therefore simply copying the class contents to another memory location is not safe. - GiNaC::ex, as far as I can tell, lacks a "duplicate" or "deep copy" routine. My current best solution, is something like: GiNaC::ex *expr, *expr_lost = new GiNaC::ex(); expr = malloc(sizeof(GiNaC::ex)); memcpy (expr, expr_lost, sizeof(GiNaC::ex)); Unfortunately, unless I take extra steps to keep track of memory pointed to by expr_lost, it gets leaked. If there is a Right Way (tm) or even just a better way to implement something like init_ex(), your advice would be much appreciated. Thanks in advance. Igor
Igor, Igor Khavkine wrote:
My current best solution, is something like:
GiNaC::ex *expr, *expr_lost = new GiNaC::ex(); expr = malloc(sizeof(GiNaC::ex)); memcpy (expr, expr_lost, sizeof(GiNaC::ex));
Unfortunately, unless I take extra steps to keep track of memory pointed to by expr_lost, it gets leaked.
I don't think you can get around those "extra steps" you mention. In C++, one has placement new for directed allocating. But you would have to write some additional code between #ifdefs to use it instead of malloc(3). And even doing so would not spare you extra destructor calls to avoid leaks. This function does not leak: void f(size_t n) { char buf[n*sizeof(GiNaC::ex)]; // you manage that memory! for (size_t i=0; i<n; ++i) { new(&buf[i*sizeof(GiNaC::ex)]) GiNaC::ex(2); } //... cout << *reinterpret_cast<GiNaC::ex*>(&buf[0 * sizeof(GiNaC::ex)]) << endl; //... // It is your responsibility to keep track of the reference counts: for (size_t i=0; i<n; ++i) { reinterpret_cast<GiNaC::ex*>(&buf[i*sizeof(GiNaC::ex)])->~ex(); } } Not sure if this helps. Regards -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
On 6/27/06, Richard B. Kreckel <kreckel@ginac.de> wrote:
I don't think you can get around those "extra steps" you mention. In C++, one has placement new for directed allocating. But you would have to write some additional code between #ifdefs to use it instead of malloc(3). And even doing so would not spare you extra destructor calls to avoid leaks. This function does not leak:
Ah, I didn't know about this feature of the new operator. It seems to do exactly what I want. Thanks!
void f(size_t n) { char buf[n*sizeof(GiNaC::ex)]; // you manage that memory! for (size_t i=0; i<n; ++i) { new(&buf[i*sizeof(GiNaC::ex)]) GiNaC::ex(2); }
//... cout << *reinterpret_cast<GiNaC::ex*>(&buf[0 * sizeof(GiNaC::ex)]) << endl; //...
// It is your responsibility to keep track of the reference counts:
Calling destructors is not a big deal. Do you mean anything else by "reference counts"? I couldn't find any documented way to access the reference counting information that GiNaC keeps internally.
for (size_t i=0; i<n; ++i) { reinterpret_cast<GiNaC::ex*>(&buf[i*sizeof(GiNaC::ex)])->~ex(); } }
Not sure if this helps.
Very much so. Thanks again! Igor
Igor, Igor Khavkine wrote:
Calling destructors is not a big deal. Do you mean anything else by "reference counts"?
No. As long as you work with objects of class ex, then carefully keeping track of allocated objects and explicit calls to the proper ex::~ex() destructors should keep your code both leak-free and running, I suppose. Clearly this is not the advertised way of using the library. But, well, since you asked...
I couldn't find any documented way to access the reference counting information that GiNaC keeps internally.
Oh, that's on purpose, because of its "internal" nature. ;-) Regards -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
participants (2)
-
Igor Khavkine
-
Richard B. Kreckel