mercredi 30 novembre 2016

Strange behavior between debug and release in Gcc5.3.0

Situation

I use GCC 5.3.0 provided by Mingw on Window 7, and gtest to implement and run unit tests.

In my project, I have a hierarchy of computers, which implements the interface Computer as below :

class Dataset; // Not

// Interface Computer
class Computer {
public:
    // Destructor virtual to enable vmap
    virtual ~Computer() noexcept = default;

    // Pure virtual fonctions
    virtual bool preCompute(Dataset &datas) const = 0;
    virtual void compute(Dataset &datas) const = 0;


};

I provide an abstract implementation of this interface as ChainableComputer, which implements another interface (Chainable) and a default implementation of precompute. See below.

class ChainableComputer : public Computer, public Chainable {
    public:
         bool preCompute(Dataset &dataset) const  override;
};

Those classes are in a namespace, called core, and packaged in core.dll

In another dll, i have implementation of ChainableComputer in another namespace domain.

Some of the implementation are simple, and don't have any thing to do in preCompute, so, they implements compute with the same way :

class SomeComputerImpl  : public ChainableComputer{
/// ...
void compute(Dataset &datas) const override final{
       auto result = preCompute(datas);
       if(!result){
          throw;
       }
}
};

This code was spreading so i decided to refactor and add a protected method in Computer :

class Computer  {
/// ...
protected:
    // Helper function for some implementations of Computer
    void doPrecomputeOrThrow(Dataset &datas) const{
       auto result = preCompute(datas);
       if(!result){
          throw;
       }
    } 
}

I don't wan't this behavior to be the default for computer, but it give me the possibility to change implementation of these computer as below :

class SomeComputerImpl  : public ChainableComputer{
/// ...
void compute(Dataset &datas) const override final{
       doPrecomputeOrThrow(Dataset &datas);
}
};

It compiles and works well in the application and in the unit test... if i compile and run in Release mode.

If I choose Debug, the compiling works, the application work, but the tests don't.

I try to understand what it could happen, but I cannot figure out what could be wrong. I guess it has something to with the linker, and the fact that the interface, an abstract implementation and the concrete implementation are in separates DLL, and that we run this stuff in another executable...

What i already try

  1. Implement a ChainableComputer directly in the test => works as expected
  2. Plays with inline or __attribute__(always_inline) on doPrecomputeOrThrow=> no effect
  3. Implementing doPrecomputeOrThrow in namespace (passing Computer * as argument), in core.dll => no effect
  4. Implementing doPrecomputeOrThrow in namespace (passing Computer * as argument), in domain.dll => works as expected
  5. Implementing doPrecomputeOrThrow as template in class or in namespace, with Computer as template parameter (see below) => works as expected
  6. Implementing doPrecomputeOrThrow as template in class, with Dataset as template parameter (see below) => no effect

    /// Template which works, as member of Computer (static or not), or /// in namespace template void doPrecomputerOrThrows(AComputer * c, Dataset& datas);

    /// Template which doesn't work, as member of Computer template void doPrecomputerOrThrows(ADataset& datas);

The Question

There is someone who have an idea of what happens ?

Aucun commentaire:

Enregistrer un commentaire