1

This is a follow-up question from this question. When I instantiate using the 'make_LSMDP2(...)' method as follows

        auto  A = make_LSMDP2(N,q,F,BM,Dr,Sine{b,c*Time},X0,R,M,T,HC_Base{T->ReturnTerm(),X0->size , length, prewidth},HC_Base{T->ReturnTerm(),X0->size , length, prewidth});

the constructor of the objects of type 'BasisY', 'BasisZ' and 'Term' works fine: I run tests in the constructors of each one to make sure they are working properly. However, when I try to use the instantiated objects, the behaviour is as though they were instantiated with random parameters, so obviously everything is a mess.

Please see this for a simple version of how the above method is implemented.

Does anyone know why this is happening? The only thing I can tell might be the problem is that I define the types 'Sine' and 'HC_Base' in a different header file to the one where I define the template method. The header, however, is included in the file where the template is constructed, so I don't see how this is a problem.

In fact, I tried to isolate the problem by developing a simple example of the 'LSMDP2' template in another project to see if there was something fundamentally wrong with the way I was constructing the class. Everything worked fine in that case. The parameter classes were simpler but used all the same data types (just to make sure that I was using the libraries correctly) as well as non-trivial constructors. The only difference I can tell is that the parameter classes and the template method were defined in the same header in that case.

If you need any further information or compiler details, please let me know!

EDIT: By request, a simplified example of the code that doesn't work: using the constructor

template<class BasisY, class BasisZ, class Term > LSMDP2<BasisY,BasisZ,Term>::LSMDP2(Term && P,  BasisY && BY1, BasisZ && BZ1) :  
    Phi(std::forward<Term>(P)) , BY(std::forward<BasisY>(BY1)), BZ(std::forward<BasisZ>(BZ1)){
BY.func_test();
}

instantiate an object using

        auto A  = make2_LSMDP2(Sine{b,c*Time},HC_Base{T->ReturnTerm(),X0->size , length, prewidth},HC_Base{T->ReturnTerm(),X0->size , length, prewidth});

where 'make2_LSMDP2(...)' just calls the simpler constructor. The constructors of 'Sine' and HC_Base are as follows:

Sine(gsl_vector * LC,double con){
    cout << "Vector dimension = " << LC->size << endl;
    LinComb = gsl_vector_alloc(LC->size);
    gsl_vector_memcpy(LinComb,LC);
    c=con;
}



HC_Base(double T /*Terminal time*/,  size_t d/*dimension*/, double width/*cube width*/, double bound/*prewidth*/) : base_f(T), CubeWidth(width),dimension(d),    pre_width (bound)
{
    func_test();
}

'base_f' is just a parent class wrapper that provides some default behaviour. In the constructor of HC_Base, a test is called which tests the performance of the instantiated object, and this works fine. The same test is called in the LSMDP2 constructor on the same object, showing entirely different behaviour! In fact, I've only shown the test on HC_Base in the constructor of LSMDP2, but I can perform similar tests with Sine that will fail.

Community
  • 1
  • 1
Plamen
  • 650
  • 1
  • 8
  • 27
  • 2
    Might not be related, but you might want to read about [the rule of three](http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29). – Some programmer dude Oct 06 '13 at 11:52
  • Can you show a (minimal) example which won't work ? – Jarod42 Oct 06 '13 at 12:08
  • 4
    No offense, but that line is horrible. Its very difficult to read. I don't want lines like these in my sourcecode, imagine its manteniance... – Manu343726 Oct 06 '13 at 12:11
  • @Jarod42 Of course, I'll add an edit. – Plamen Oct 06 '13 at 12:22
  • @Manu343726 I know, I have a method requiring a lot of polymorphism and it's useful to keep it as abstract as possible. The maintenance is not too bad, in fact, as it's quite easy to test the components individually and most of the work is done in that one line! – Plamen Oct 06 '13 at 12:53
  • 1
    I suppose that `~Sine` release `LinComb`, that the rule of 5 (3+move) is not respected. Do you have a move/copy constructor ? – Jarod42 Oct 06 '13 at 13:02
  • @Jarod42 for Sine and HC_Base? No. They have destructors. Nevertheless, the constructor I use in the instantiation of A is well defined, there is no copying/moving... Is this still an issue? – Plamen Oct 06 '13 at 13:14
  • I suggest you to test that by adding `Sine(Sine&&)=delete;` (or some logging if unsupported).(same with copy constructor and (move)assignment). Also, try to provide a complete failing sample, you provide a working example, and some part of your code... – Jarod42 Oct 06 '13 at 13:31
  • @Jarod42 you were absolutely right! Thanks! The LSMDP2 constructor was calling a move constructor, leading to undefined behaviour. Could you out your comments up as an answer so I can mark it right and you can get your well earned exp points? – Plamen Oct 07 '13 at 05:36

1 Answers1

1

I suppose that ~Sine release LinComb, that the rule of 5 (3+move) is not respected.

You should so implement (or forbid with =delete):

  • Sine(const Sine&)
  • Sine& operator=(const Sine&)
  • Sine(Sine&&);
  • Sine& operator=(Sine&&)
Jarod42
  • 203,559
  • 14
  • 181
  • 302