CVM Class Library Frequently Asked Questions
How does it share memory between objects and why?
Sharing memory (or shallow copying) is a practice allowing to avoid unnecessary memory allocations and dealocations.
For example, the following code
rmatrix m(3,4);
rvector v(4);
...
m[2]=v;
assigns vector v to second row of matrix m by returning a new
rvector object sharing memory with the row and assigning elements of v to it.
There is just one constructor per each class making shallow copy (see documentation for more details).
For example, rvector's one is
rvector::rvector (TR* pD, int nSize, int nIncr = 1);
However, since version 6.0 the library is no longer using embedded memory manager for performance reasons.
This created a problem of sharing memory which no longer exists. Let's consider the following code:
cvector low_up_diag (const scmatrix& m, iarray& naPivots)
{
return m.low_up(naPivots).diag(0);
}
Here low_up creates a temporary matrix, then diag returns a vector
sharing memory with its main diagonal. Despite returning it from this function by value,
copy vonstructor will not be executed here. As a result, cvector with dangling pointer
inside will be returned. To resolve this issue second constructor making deep copy was created since version 6.0,
here its signature for rvector:
rvector::rvector (const TR* pD, int nSize, int nIncr = 1);
This second flavor accepts pointer to const treal (treal is typedef-ed as double or float). So the code above should be written as the following:
cvector low_up_diag (const scmatrix& m, iarray& naPivots)
{
const scmatrix lu = return m.low_up(naPivots);
return lu.diag(0);
}
Declaring the temporary matrix lu as const guarantees calling
the second version of the constructor, therefore new chunk of memory gets allocated.
Why does A=B+C; expression create a temporary object and how to avoid this?
This library was created in those times when not every C++ compiler supported templates.
There are modern template-based technics allowing to avoid such temporary allocations, but CVM still
uses "old fashion way" for backward compatibility and better stability (at least so far).
If you compare this memory allocation cost with any algorithm you might use down he road
(like eigenvalues problem) you'd see that it costs almost nothing. However, if your code
deals with many small objects, this might become a performance issue. In such cases use
member functions (like A.sum(B,C);) instead of operators.
Why does printf("%g", m(1,1)); print garbage?
Because m(1,1) and any other matrix indexing operator do not return treal
(typedef-ed as double or float) type. They return proxy type instead.
That's because the library needs to make sure that by changing particular
matrix element your code never changes object's integrity. For example, if you change an element
of symmetric matrix outside of its main diagonal then this matrix would no longer be symmetric.
To avoid this the library uses type proxies whch throw cvmexception
in case of attempt to break object's integrity. Unfortunately, printf
is not able to recognize those proxies (and after all this is not C++ but C style,
so try to avoid it). There are two ways to resolve this: use either
std::cout << m(1,1);
or
printf("%g", m(1,1).val());
Why does Intel C++ compiler fail to compile the code under Linux?
Unfortunately current version 11.1 doesn't support C++ TR1 system headers on a system with g++ version 4.3 or later installed,
see more details in their official report.
It works under Windows only so far. Hopefully they'll fix this in next release.
Currently you may use g++ compiler (and it's perfectly mixable with Intel Fortran).
Copyright (c) Sergei Nikolaev, 1992-2010. Welcome to my personal
page.
Back to the Library