eranpeer / FakeIt

C++ mocking made easy. A simple yet very expressive, headers only library for c++ mocking.
MIT License
1.24k stars 170 forks source link

make_shared does not work for a Mock<T> object #45

Closed Rupsbant closed 8 years ago

Rupsbant commented 8 years ago

When compiling with clang 3.6.1 on OSX std::make_shared has a problem with the THROWS macro in the destructors of Mock. I have also tried Linux with GCC and clang (also 3.6.1), OSX with GCC. There the compiler doesn't complain.

Removing noexcept(false) compiles, probably because it defaults to the most strict declaration (noexcept(true)) if possible. Changing THROWS to NO_THROWS also work for me. But probably this is because I didn't use any exceptions in my project yet. I'm curious to an application.

Minimal example:

#include <fakeit.hpp>
#include <memory>
using namespace fakeit;
using namespace std;
struct T {
    int x;
    T(int x) : x(x) {}
    virtual int get() {return x;}
};
int main() {
    shared_ptr<Mock<T>> shm= make_shared<Mock<T>>();
}

Full stack trace:

/usr/local/Cellar/llvm/3.6.1/bin/../include/c++/v1/memory:3690:7: error: exception specification of overriding function is more lax than base version class shared_ptr_emplace ^ /usr/local/Cellar/llvm/3.6.1/bin/../include/c++/v1/memory:4280:26: note: in instantiation of template class 'std::1::shared_ptr_emplacefakeit::Mock<BoolTerm, std::1::allocatorfakeit::Mock >' requested here ::new(hold2.get()) _CntrlBlk(a2, std::1::forward<_Args>(args)...); ^ /usr/local/Cellar/llvm/3.6.1/bin/../include/c++/v1/memory:4644:29: note: in instantiation of function template specialization 'std::1::shared_ptrfakeit::Mock::make_shared<>' requested here return shared_ptr<_Tp>::make_shared(std::__1::forward<_Args>(args)...); ^ idp4/tests/solver/../MockFactory.hpp:37:14: note: in instantiation of function template specialization 'std::__1::make_sharedfakeit::Mock' requested here shared_ptr<Mock> out(make_shared<Mock>());

eranpeer commented 8 years ago

Well, I'm not an OSX guy. I don't even have a MAC. (Or any other OSX device) It will be hard for me to fix this one (because I can't reproduce it). It looks like a compiler issue. I've never thought about a scenario of creating a shared_ptr of a mock object. I'm just being curious, Why do you need such a shared_ptr?

Rupsbant commented 8 years ago

Because we have a non-trivial directed acyclic graph at the core that needs automatic memory management and we don't want to write our own reference counting or garbage collector (since none of us know how and generally this has a high failure rate).

The majority of future developers will come with a background of languages with gc. So we need to define the memory model up-front to avoid mistakes.

The shared pointer for the mocks is not really needed but keeps the same style as the rest. A unique pointer could also be used but probably generates the same errors.

And because I completely forgot until I saw the trace again:

Mock<T>* m = new Mock<T>();
std::shared_ptr<Mock<T>>(m);

does work for us. So problem solved on our end, we don't really need the make_shared performance for tests.

eranpeer commented 8 years ago

OK, I replaced the THROWS with NO_THROWS. It is better this way since the dtor of the mock should not throw any exception anyway. Checkout the latest copy. It should compile now. Please update me if it solved/didn't solve your problem.

Matthiasvanderhallen commented 8 years ago

As Rupsbant seems to have forgotten this: I work on the same project and it did indeed solve the problem. Thank you eranpeer.