Misleading Vector copy constructor

Issue #445 new
Felix Ospald created an issue

There is an wrapping issue when creating a copy of a Vector, i.e.

std::shared_ptr<GenericVector> a(new Vector(MPI_COMM_WORLD, 5));
std::shared_ptr<GenericVector> b(new Vector(*a));

a is an instance of Vector which wraps usually an PETScVector (accessible by a->instance()) b is an instance of Vector which wraps an Vector which wraps an PETScVector.

Performing now operations like

(*a) += (*b);

will cause an error within the "as_type" method. The += operator is called on Vector which calls the += on PETScVector with an GenericVector as argument. This tries to cast the right hand side (*b) to an PETScVector via "as_type", returning a

dynamic_cast<PETScVector&>(*b->instance());

However this fails since b->instance() is of type Vector.

The complete issue is caused by the GenericVector constructor of Vector

Vector(const GenericVector& x) : vector(x.copy()) {}

which wraps any GenericVector, also if it is an Vector.

It would be more logical to have an constructor like this:

Vector::Vector(const GenericVector& x) {
    const Vector* vec = dynamic_cast<Vector*>(&x);
    if (vec != NULL) {
             vector.reset(vec->vector->copy());
        }
        else {
             vector.reset(x.copy());
        }
}

which would also be consistent with the copy constructor of Vector

Vector(const Vector& x) : vector(x.vector->copy()) {}

Here some additional code for testing:

#include <dolfin/la/dolfin_la.h>
#include <cxxabi.h>

#define TYPEOF(a) std::cout << "Type of " << #a << " is " << demangled_type_info_name(typeid(a)) << std::endl

// see http://stackoverflow.com/a/19005835
static inline std::string demangled_type_info_name(const std::type_info&ti)
{
    int status = 0;
    return abi::__cxa_demangle(ti.name(),0,0,&status);
}

using namespace dolfin;

main() {
    std::shared_ptr<GenericVector> a (new Vector(MPI_COMM_WORLD, 5));

    TYPEOF(*a);
    TYPEOF(*a->instance());
    std::cout << std::endl;

    std::shared_ptr<GenericVector> b(new Vector(*a)); 

    TYPEOF(*b);
    TYPEOF(*b->instance());
    TYPEOF(*dynamic_cast<Vector*>(b->instance())->instance());
    std::cout << std::endl;

    std::shared_ptr<GenericVector> c(a->copy()); 

    TYPEOF(*c);
    TYPEOF(*c->instance());
}

Comments (4)

  1. Log in to comment