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