unique_ptr and cleanup when membership is transferred during a test

3,004 views
Skip to first unread message

Alex Shaver

unread,
Jan 9, 2015, 4:32:24 PM1/9/15
to googl...@googlegroups.com
Suppose I have a class Foo, into which I inject overloaded classes it will use:
class A{};
class Alpha : public A{};
class Aleph : public A{};

class B{};
class Beta : public B{};
class Beth : public B{};

class Foo{
public:
 
Foo(A* a, B* b) :
    _A
(a),
    _B
(b)
   
{}

private:
std
::unique_ptr<A> _A;
std
::unique_ptr<B> _B;
}

When I'm writing a test, suppose I have
class MockA{} : public A{};
class MockB{} : public B{};

Test(FooTest, Foo){
 
MockA mockA;
 
MockB mockB;
 
Foo foo(&mockA, &mockB);
}

I don't think this is right from what I think I know about unique_ptr (namely that Foo can't take ownership since they're objects within that test function?). In any event, the program crashes when it tries to delete Foo. It can't use the default destructor. (looking through the gdb stuff)

So, let's try what I thought was the better approach
class MockA{} : public A{};
class MockB{} : public B{};

Test(FooTest, Foo){
  std
::unique_ptr<MockA>(mockA);
 
MockA _mockA = mockA.get();
  std
::unique_ptr<MockB>(mockB);
 
 
Foo foo(mockA.release(), mockB.release());

  EXPECT_CALL
(*_mockA, bar()); //where bar is some mocked out function. Need _mockA since mockA is now a nullptr after the release
 
/*...more test stuff*/
}

This time the program doesn't crash. But it does complain afterward that the mock objects mockA, mockB should be deleted but never are. But their ownership is transferred to Foo, who is now responsible for deleting them, and should delete them when it is destroyed, no?

In any event I've tried a wide number of variations of these tests... and it seems to be a conflict with Google Tests trying to clean themselves up and the smart cleanup provided by unique_ptr. 

Keith Ray

unread,
Jan 9, 2015, 5:26:35 PM1/9/15
to Alex Shaver, googl...@googlegroups.com
It looks really hard, since no two unique_ptr instances can manage the same object. But the constructor isn't taking unique_ptr objects. But unique_ptr instance MUST take a pointer allocated by 'new'.

This should work:

Test(FooTest, Foo){
  MockA *mockA = new MockA;
  MockB *mockB = new MockB;

  EXPECT_CALL(*mockA, bar()); // this must be called before passing
    // objects into the code to be tested.

  Foo foo(&mockA, &mockB); // code to be tested...

  // When foo goes out of scope, its destructor will delete mockA and mockB.
}
--

---
You received this message because you are subscribed to the Google Groups "Google C++ Mocking Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/googlemock/623e471e-6561-44d7-ab56-fd70de7f51f1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Keith Ray

unread,
Jan 9, 2015, 5:28:28 PM1/9/15
to Alex Shaver, <googlemock@googlegroups.com>
syntax correction 

Test(FooTest, Foo){
  MockA *mockA = new MockA;
  MockB *mockB = new MockB;

  EXPECT_CALL(*mockA, bar()); // this must be called before passing
    // objects into the code to be tested.

  Foo foo(mockA, mockB); // [corrected] code to be tested...


  // When foo goes out of scope, its destructor will delete mockA and mockB.
}


Billy Donahue

unread,
Jan 10, 2015, 10:11:31 AM1/10/15
to Keith Ray, Alex Shaver, <googlemock@googlegroups.com>

It feels like this whole question would be a lot clearer or even dodged entirely if Foo::Foo(A*,B*) were written as Foo::Foo(std::unique_ptr<A>, std::unique_ptr<B>). Make the ownership transfer explicit, and the double-free bug wouldn't even compile, right?  If you can change Foo's constructors, I would do that.

BTW, you can't use leading underscores followed by capital letters.
Those are reserved in C++. Fixed below.

class Foo {
 public:
  Foo(std::unique_ptr<A> a, std::unique_ptr<B> b)
      : a_(std::move(a)), b_(std::move(b)) {}
 private:
  std::unique_ptr<A> a_;
  std::unique_ptr<B> b_;
};

class MockA : public A {};
class MockB : public B {};

Test(FooTest, Foo){
  auto mock_a = std::make_unique<MockA>();
  auto mock_b = std::make_unique<MockB>();

  EXPECT_CALL(*mock_a, bar());

  Foo foo(std::move(mock_a), std::move(mock_b));
}


PPPPS: ב is "bet" with no "h".  :^)


On Fri, Jan 9, 2015 at 5:28 PM, Keith Ray <keit...@gmail.com> wrote:
syntax correction 

Test(FooTest, Foo){
  MockA *mockA = new MockA;
  MockB *mockB = new MockB;

  EXPECT_CALL(*mockA, bar()); // this must be called before passing
    // objects into the code to be tested.

  Foo foo(mockA, mockB); // [corrected] code to be tested...

  // When foo goes out of scope, its destructor will delete mockA and mockB.
}
On 2015 Jan 09, at 2:26 PM, Keith Ray <keit...@gmail.com> wrote:

Alex Shaver

unread,
Jan 13, 2015, 1:57:10 PM1/13/15
to googl...@googlegroups.com, alexs...@gmail.com
The problem with this approach is that I can't then use a common test framework. Each test will have different EXPECT_CALLs associated with them. Billy, below I think has the right approach as far as I can tell, I think.

Keith Ray

unread,
Jan 13, 2015, 2:31:12 PM1/13/15
to Alex Shaver, <googlemock@googlegroups.com>

On 2015 Jan 13, at 10:57 AM, Alex Shaver <alexs...@gmail.com> wrote:

Each test will have different EXPECT_CALLs associated with them

That's what we usually do in unit testing.

Alex Shaver

unread,
Jan 13, 2015, 2:54:08 PM1/13/15
to googl...@googlegroups.com, keit...@gmail.com, alexs...@gmail.com
When I do this, the test program crashes. GMock tries to put a mutex lock around the object, and the std::move breaks that mutex, I believe.

(also I know it's bet, but I like things to have same lengths :) )

Alex Shaver

unread,
Jan 13, 2015, 2:55:48 PM1/13/15
to googl...@googlegroups.com, alexs...@gmail.com
True. But the paradigm where I must call several EXPECT_CALLs before passing them into the function somewhat obliviates the ability to create test frameworks with common SetUp and TearDown functions. Not entirely, but it's a little wonky compared to the normal use scenario.

Keith Ray

unread,
Jan 13, 2015, 3:11:29 PM1/13/15
to Alex Shaver, googl...@googlegroups.com
You can create mocks objects in SetUp and call EXPECT_CALL on them, etc.

You can also put EXPECT_CALLs in the constructors of your mock classes, or in other test-only methods.
-- 

--- 
You received this message because you are subscribed to the Google Groups "Google C++ Mocking Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.

Billy Donahue

unread,
Jan 13, 2015, 3:13:43 PM1/13/15
to Alex Shaver, googl...@googlegroups.com, Keith Ray
On Tue, Jan 13, 2015 at 2:54 PM, Alex Shaver <alexs...@gmail.com> wrote:
When I do this, the test program crashes. GMock tries to put a mutex lock around the object, and the std::move breaks that mutex, I believe.

I don't follow that.  Gmock's mutexes are locked and unlocked as leaf locks. I don't see how std::move on a unique_ptr would change the pointee. Needs more investigation.

Alex Shaver

unread,
Jan 13, 2015, 3:34:18 PM1/13/15
to googl...@googlegroups.com, alexs...@gmail.com, keit...@gmail.com
I have a code sample up at https://bitbucket.org/alex_shaver/googletest-uniqueptr

essentially: 
class A{
 
virtual void Arc() = 0;
};

class Mock_A : public A{
  MOCK_METHOD0
(Arc, void());
};

class Foo{
protected:
 
Foo(std::unique_ptr<A> a) : _A(std::move(a)){}
  std
::unique_ptr<A> _A;

 
void DoStuff(){ _A->Arc(); }
}

TEST
(FooTest, DoStuff){
  std
::unique_ptr<Mock_A> mock_a;
  EXPECT_CALL(*mock_a, Arc());
  foo
(std::move(mock_a));
  foo.DoStuff();
}

 throws an exception

Billy Donahue

unread,
Jan 13, 2015, 3:55:44 PM1/13/15
to Alex Shaver, googl...@googlegroups.com, keit...@gmail.com
mock_a is null. you have to set it to the address of an allocated instance of MockA
--

---
You received this message because you are subscribed to the Google Groups "Google C++ Mocking Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/googlemock/15dc5411-903c-4aa0-813e-3a9ce14624bd%40googlegroups.com.

Keith Ray

unread,
Jan 13, 2015, 4:04:20 PM1/13/15
to Alex Shaver, googl...@googlegroups.com
I'm pretty sure that the problem is that there are still two owners of an object, and two attempts to destruct that object, violating unique_ptr's contract. One owner might be the mocking infrastructure. Can you change the code to use shared_ptr instead of unique_ptr? If you use shared_ptr, and *never* pass the raw pointer around, you should be able to avoid the double-destruct crash.

--
C. Keith Ray
650-533-6535
http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
http://agilesolutionspace.blogspot.com/

Keith Ray

unread,
Jan 13, 2015, 4:07:59 PM1/13/15
to Billy Donahue, Alex Shaver, googl...@googlegroups.com
Yup. Must allocate raw pointer to pass into unique_ptr.

I could be wrong, but I think the mocking infrastructure *requires* shared access to the mock objects. unique_ptr gets in the way of that. 

--
C. Keith Ray
650-533-6535
http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
http://agilesolutionspace.blogspot.com/

Alex Shaver

unread,
Jan 13, 2015, 4:51:26 PM1/13/15
to googl...@googlegroups.com, billyd...@google.com, alexs...@gmail.com
Right, and this is where I think there's a flaw in the implementation of the testing/mocking infrastructure. The reality, in my actual code, is that it really should be a unique_ptr. Changing it to shared is architecturally incorrect. 

In fact (and a new version of this test suite was uploaded to that repo for example) shared_ptr also throws an error.

class Bar{
public:
 
Bar(std::shared_ptr<A> a) : _A(a){}
 
~Bar() = default;
 
void DoStuff(){ _A->Arc(); }

  std
::shared_ptr<A> _A;
}

TEST
(Bar, DoStuff){
  std
::shared_ptr<Mock_A> Alice;
  EXPECT_CALL
(*Alice, Arc());
 
Bar bar(Alice);
  bar
.DoStuff()
}


throws an error too.

I think, fundamentally, google test seems broken when injecting smart pointers to mock objects. Which is a big flaw for certain design schema, if I want to transfer memory management between objects.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+unsubscribe@googlegroups.com.

Billy Donahue

unread,
Jan 13, 2015, 5:06:55 PM1/13/15
to Alex Shaver, googl...@googlegroups.com
On Tue, Jan 13, 2015 at 4:51 PM, Alex Shaver <alexs...@gmail.com> wrote:
Right, and this is where I think there's a flaw in the implementation of the testing/mocking infrastructure. The reality, in my actual code, is that it really should be a unique_ptr. Changing it to shared is architecturally incorrect. 

In fact (and a new version of this test suite was uploaded to that repo for example) shared_ptr also throws an error.

class Bar{
public:
 
Bar(std::shared_ptr<A> a) : _A(a){}
 
~Bar() = default;
 
void DoStuff(){ _A->Arc(); }

  std
::shared_ptr<A> _A;
}

TEST
(Bar, DoStuff){
  std
::shared_ptr<Mock_A> Alice;
  EXPECT_CALL
(*Alice, Arc());
 
Bar bar(Alice);
  bar
.DoStuff()
}


throws an error too.

I think, fundamentally, google test seems broken when injecting smart pointers to mock objects. Which is a big flaw for certain design schema, if I want to transfer memory management between objects.

Why do you think "*Alice" is a valid expression?  It's a shared_ptr<Mock_A> that's been default-initialized and holds null.
I haven't seen a flaw in GMock yet. If there is one, we can talk about it, for sure.

Keith Ray

unread,
Jan 13, 2015, 7:33:12 PM1/13/15
to Alex Shaver, googl...@googlegroups.com
"Thinking something does not make it true. Wanting something does not make it real.” 
― Michelle HodkinThe Unbecoming of Mara Dyer


"Since we cannot change reality, let us change the eyes which see reality." — Nikos Kazantzakis

YMMV
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/googlemock/CAPdGrqq8Yjm3Q34d9Ak%2BBywFa8DJr6wizxehHJcxOeX-qLb5fw%40mail.gmail.com.

Alex Shaver

unread,
Jan 14, 2015, 9:32:41 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
Sorry, I just don't have as much experience with the shared_ptr paradigm. But even so, it is an architecturally incorrect choice. 

Simply put, Does Google Mock support injection of objects managed by unique_ptr? I don't think so. I certainly welcome a suggestion on how I could properly implement it... but it does seem that google test's clean-up routines, which may be admirable in many other use scenarios, aren't working in a quite reasonable case of injecting smart-memory objects. That is a broken behaviour, if true.

Billy Donahue

unread,
Jan 14, 2015, 9:37:39 AM1/14/15
to Alex Shaver, googl...@googlegroups.com
On Wed, Jan 14, 2015 at 9:32 AM, Alex Shaver <alexs...@gmail.com> wrote:
Sorry, I just don't have as much experience with the shared_ptr paradigm. But even so, it is an architecturally incorrect choice. 

I recommend gaining a little more experience with C++ before making such confident claim about a very technical library.

 
Simply put, Does Google Mock support injection of objects managed by unique_ptr? I don't think so. I certainly welcome a suggestion on how I could properly implement it... but it does seem that google test's clean-up routines, which may be admirable in many other use scenarios, aren't working in a quite reasonable case of injecting smart-memory objects. That is a broken behaviour, if true.

What started as a strident claim of incorrectness has just been downgraded to a qualified conditional.
It's on a false condition, actually. GMock tracks the mock object by identity (address). The pointer schemes you use to manage other pointers to it across your software are irrelevant to gmock.

I'd still like to see a concrete complaint if there is one.
 

Alex Shaver

unread,
Jan 14, 2015, 10:03:10 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
I posted a code example several times throughout this discussion, as well as uploaded the exact code that fails to run. I am a little put off at the "help" being offered in such accusatory terms. I don't have much experience with shared_ptr, true. But that was just an experiment to see if such a thing was feasible in the first place. I have more experience with unique_ptr, and I simply have not found a way to make the correct production and test code in that case.

Here is the "concrete complaint" if you wish:

class A{
public: virtual void Arc() = 0;
};

class Mock_A : public A{
public: MOCK_METHOD0(Arc, void());
};

class Foo{
public:
 
Foo(std::unique_ptr<A> a) : _A(std::move(a));
 
void DoStuff(){_A->Arc();}
  std
::unique_ptr<A> _A;
};

TEST
(Foo, DoStuff){

  std
::unique_ptr<Mock_A> mock_a;
  EXPECT_CALL
(*mock_a, Arc());

 
Foo foo(std::move(mock_a));
  foo
.DoStuff();
}


That code will fail. I've tried alternatives (again, as mentioned above in several various iterations) including copying the pointer, using just a pointer (not a unique_ptr) to pass into the constructor, and others. If there is a way, I would sincerely appreciate assistance. Something to help me see what I'm missing. 

It is only if there is not some way to do this that I think something is not working with the google test framework. Between my own knowledge and the people who made the framework, I expect it's an error on my end. But I cannot, for the life of me, see what it is.

Tamas Berghammer

unread,
Jan 14, 2015, 10:27:06 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
Gmock supports what you want to achieve and your snippet is the right way to do it. You experience a crash and a leak because of the following bugs in your snippet:
  • mock_a isn't initialized (cause segfault)
  • class A don't have virtual destructor (leak of mock object)
  • (Missing body for Foo constructor)
The fixed version of your snippets works fine for me:
class A{
public:
    virtual ~A() {}
    virtual void Arc() = 0;
};

class Mock_A : public A{
public:
    MOCK_METHOD0(Arc, void());
};

class Foo{
public:
    Foo(std::unique_ptr<A> a) : _a(std::move(a)) {}
    void DoStuff(){ _a->Arc(); }
    std::unique_ptr<A> _a;
};

TEST(Foo, DoStuff){
    std::unique_ptr<Mock_A> mock_a(new Mock_A());
...

Billy Donahue

unread,
Jan 14, 2015, 10:28:11 AM1/14/15
to Alex Shaver, googl...@googlegroups.com
On Wed, Jan 14, 2015 at 10:03 AM, Alex Shaver <alexs...@gmail.com> wrote:
I posted a code example several times throughout this discussion, as well as uploaded the exact code that fails to run. I am a little put off at the "help" being offered in such accusatory terms. I don't have much experience with shared_ptr, true. But that was just an experiment to see if such a thing was feasible in the first place. I have more experience with unique_ptr, and I simply have not found a way to make the correct production and test code in that case.

"But even so, it is an architecturally incorrect choice. "

You actually don't know that, and I've tried to help you a few times.

 
Here is the "concrete complaint" if you wish:

class A{
public: virtual void Arc() = 0;
};

class Mock_A : public A{
public: MOCK_METHOD0(Arc, void());
};

class Foo{
public:
 
Foo(std::unique_ptr<A> a) : _A(std::move(a));
 
void DoStuff(){_A->Arc();}
  std
::unique_ptr<A> _A;
};

TEST
(Foo, DoStuff){
  std
::unique_ptr<Mock_A> mock_a;
  EXPECT_CALL
(*mock_a, Arc());

 
Foo foo(std::move(mock_a));
  foo
.DoStuff();
}


That code will fail. I've tried alternatives (again, as mentioned above in several various iterations) including copying the pointer, using just a pointer (not a unique_ptr) to pass into the constructor, and others. If there is a way, I would sincerely appreciate assistance. Something to help me see what I'm missing. 

It is only if there is not some way to do this that I think something is not working with the google test framework. Between my own knowledge and the people who made the framework, I expect it's an error on my end. But I cannot, for the life of me, see what it is.

I've already told you what's wrong with that code, though, and your response was to make a claim about Gmock's "architecturally incorrect choice" instead of actually trying to implement the suggestion.

You have C++ problems, not Gmock problems. That's fine, but please hold off on widening the discussion to Gmock's architecture w.r.t. smart pointers until you've got enough experience to know whether that's true or not.

You need to put something in the unique_ptr before dereferencing it.
Imagine:

Mock_A* mock_a = nullptr;
EXPECT_CALL(*mock_a, Arc());

This is hopefully more obviously wrong.



 

Alex Shaver

unread,
Jan 14, 2015, 10:30:12 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
I've uploaded several variants to the repository https://bitbucket.org/alex_shaver/googletest-uniqueptr. This includes GDB backtraces and google test output. 

The closest I can get to a sane compiling program that warps, but not breaks, my code design is the following: 

class A{
 
public: virtual void Arc() = 0;
];

class Mock_A : public A{
 
public:

   
Mock_A() = default;
   
virtual ~Mock_A() = default;

    MOCK_METHOD0
(Arc, void());
};

class Foo{
public:

 
Foo(A* a) : _A(std::move(a)){}

 
void DoStuff(){ _A->Arc(); }

std
::unique_ptr<A> _A;
};

TEST
(Foo, DoStuff){

 
Mock_A* Alice = new Mock_A();
  EXPECT_CALL(*Mock_A, Arc());
 
Foo foo(Alice);
  foo.DoStuff();
};

which only gives me a

/home/amshaver/UniquePtrTesting/Test/UniquePtrTesting_TEST/main.cpp:34: ERROR: this mock object (used in test Foo.DoStuff) should be deleted but never is. Its address is @0x2250820.
ERROR: 1 leaked mock object found at program exit.

error in the test.
...

Alex Shaver

unread,
Jan 14, 2015, 10:39:25 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
I've already told you what's wrong with that code, though, and your response was to make a claim about Gmock's "architecturally incorrect choice" instead of actually trying to implement the suggestion.
You have C++ problems, not Gmock problems. That's fine, but please hold off on widening the discussion to Gmock's architecture w.r.t. smart pointers until you've got enough experience to know whether that's true or not.
You need to put something in the unique_ptr before dereferencing it.
Imagine:
Mock_A* mock_a = nullptr;
EXPECT_CALL(*mock_a, Arc());
This is hopefully more obviously wrong.

right, and I have gotten, throughout, why it is wrong. Obviously, that google test would now see it as a null ptr it can't be used.
So... if it is now a nullptr... how then can I handle it in Google Test so that I can access it for the sake of mock injections? If the ownership is completely within the Foo object, and mock_a now points to null... How am I supposed to use it?

 I have tried to instead do something like:

TEST(){
  std
::unique_ptr<Mock_A> mock_A;
  Mock_A* _mock_A = mock_A.get();
  EXPECT_CALL
(*_mock_A, Arc());
  Foo foo(std::move(mock_A));
  foo.DoStuff();
}

that has also failed. ie, I'm trying to keep a record, as it were, of that object's address, and use the expect_call on that recorded address, but that also fails.
...

Billy Donahue

unread,
Jan 14, 2015, 10:42:20 AM1/14/15
to Alex Shaver, googl...@googlegroups.com
On Wed, Jan 14, 2015 at 10:30 AM, Alex Shaver <alexs...@gmail.com> wrote:
I've uploaded several variants to the repository https://bitbucket.org/alex_shaver/googletest-uniqueptr. This includes GDB backtraces and google test output. 

The closest I can get to a sane compiling program that warps, but not breaks, my code design is the following: 

class A{
 
public: virtual void Arc() = 0;
];

class Mock_A : public A{
 
public:

   
Mock_A() = default;
   
virtual ~Mock_A() = default;

    MOCK_METHOD0
(Arc, void());
};

class Foo{
public:

 
Foo(A* a) : _A(std::move(a)){}
 
void DoStuff(){ _A->Arc(); }

std
::unique_ptr<A> _A;
};

TEST
(Foo, DoStuff){

 
Mock_A* Alice = new Mock_A();
  EXPECT_CALL(*Mock_A, Arc());
 
Foo foo(Alice);
  foo.DoStuff();
};

which only gives me a

/home/amshaver/UniquePtrTesting/Test/UniquePtrTesting_TEST/main.cpp:34: ERROR: this mock object (used in test Foo.DoStuff) should be deleted but never is. Its address is @0x2250820.
ERROR: 1 leaked mock object found at program exit.

error in the test.

Okay, now we're talking:

  Mock_A* Alice = new Mock_A();
  EXPECT_CALL(*Mock_A, Arc());

Doesn't compile. Did you mean EXPECT_CALL(*Alice, Arc()) ?

Doing a std::move on a raw pointer doesn't help you either in the Foo::Foo(A*) ctor.
It's still pretty weird looking.
 

--

---
You received this message because you are subscribed to the Google Groups "Google C++ Mocking Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.

Billy Donahue

unread,
Jan 14, 2015, 10:47:45 AM1/14/15
to Alex Shaver, googl...@googlegroups.com
On Wed, Jan 14, 2015 at 10:39 AM, Alex Shaver <alexs...@gmail.com> wrote:
I've already told you what's wrong with that code, though, and your response was to make a claim about Gmock's "architecturally incorrect choice" instead of actually trying to implement the suggestion.
You have C++ problems, not Gmock problems. That's fine, but please hold off on widening the discussion to Gmock's architecture w.r.t. smart pointers until you've got enough experience to know whether that's true or not.
You need to put something in the unique_ptr before dereferencing it.
Imagine:
Mock_A* mock_a = nullptr;
EXPECT_CALL(*mock_a, Arc());
This is hopefully more obviously wrong.

right, and I have gotten, throughout, why it is wrong.

Okay, but it's still your "concrete example". Why is that?
It's hard to look past the errors and try to figure out what your Gmock complaint really is.

You've provided code that doesn't compile and claimed that it compiles and gives you runtime errors from Gmock. So we're stuck trying to figure out what exactly is the Gmock problem you're seeing.

Obviously, that google test would now see it as a null ptr it can't be used.

It's too lage. GMock never even sees it. By the time *mock_a appears, the program had taken a one-way trip to undefined behavior land, and we can't make sense of what happens next.

So... if it is now a nullptr... how then can I handle it in Google Test so that I can access it for the sake of mock injections? If the ownership is completely within the Foo object, and mock_a now points to null... How am I supposed to use it?

You can't make expectations on *nullptr. 

--

---
You received this message because you are subscribed to the Google Groups "Google C++ Mocking Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.

Alex Shaver

unread,
Jan 14, 2015, 10:50:35 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
Okay, I definitely had one big glaring error in my prior code. In my attempt to abstract out from my real-world situation, I had forgotten to define constructors and destructors for the class Mock_A;

So, once more into the breach, I have been able to recover (what I think, at least) to be the right production code design.

class Mock_A{

 
Mock_A() = default;
 
virtual ~Mock_A() = default;

  MOCK_METHOD0
(Arc, void());
}

class Foo{

 
Foo(std::unique_ptr<A> alice) : Alice(std::move(alice)){};
 
virtual ~Foo() = default;

 
void DoStuff(){ Alice->Arc(); }

  std
::unique_ptr<A> Alice;
}

TEST
(Foo, DoStuff){
    std::unique_ptr<Mock_A> Alice(new Mock_A());
    EXPECT_CALL(*Alice, Arc());

    Foo foo(std::move(Alice));

    foo.DoStuff();
}

This works, but still returns the stuff about not deleting the object

/home/amshaver/UniquePtrTesting/Test/UniquePtrTesting_TEST/main.cpp:23: ERROR: this mock object (used in test Foo.DoStuff) should be deleted but never is. Its address is @0x20ce820.
ERROR: 1 leaked mock object found at program exit.

I do, of course, sincerely appreciate the help you've provided so far. But this remains my last little sticking point. This isn't *really* an error. The test does pass, of course. So I'm glad of that. But it would be awkward, I suspect, in a larger test suite, to know if and when there was an actual memory leak, and when it's this moved pointer issue. 
...

Alex Shaver

unread,
Jan 14, 2015, 10:52:07 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
(note too, I was rewriting code into the group text space rather than copy pasting. So the above compiler errors were just my mistranslation from code to post. )
...

Billy Donahue

unread,
Jan 14, 2015, 10:56:21 AM1/14/15
to Alex Shaver, googl...@googlegroups.com
On Wed, Jan 14, 2015 at 10:52 AM, Alex Shaver <alexs...@gmail.com> wrote:
(note too, I was rewriting code into the group text space rather than copy pasting. So the above compiler errors were just my mistranslation from code to post. )


On Wednesday, January 14, 2015 at 10:50:35 AM UTC-5, Alex Shaver wrote:
Okay, I definitely had one big glaring error in my prior code. In my attempt to abstract out from my real-world situation, I had forgotten to define constructors and destructors for the class Mock_A;

So, once more into the breach, I have been able to recover (what I think, at least) to be the right production code design.

class Mock_A{
 
Mock_A() = default;
 
virtual ~Mock_A() = default;

  MOCK_METHOD0
(Arc, void());
}

class Foo{
 
Foo(std::unique_ptr<A> alice) : Alice(std::move(alice)){};
 
virtual ~Foo() = default;

 
void DoStuff(){ Alice->Arc(); }

  std
::unique_ptr<A> Alice;
}

TEST
(Foo, DoStuff){
    std::unique_ptr<Mock_A> Alice(new Mock_A());
    EXPECT_CALL(*Alice, Arc());

    Foo foo(std::move(Alice));

    foo.DoStuff();
}

This works, but still returns the stuff about not deleting the object

/home/amshaver/UniquePtrTesting/Test/UniquePtrTesting_TEST/main.cpp:23: ERROR: this mock object (used in test Foo.DoStuff) should be deleted but never is. Its address is @0x20ce820.
ERROR: 1 leaked mock object found at program exit.

I do, of course, sincerely appreciate the help you've provided so far. But this remains my last little sticking point. This isn't *really* an error. The test does pass, of course. So I'm glad of that. But it would be awkward, I suspect, in a larger test suite, to know if and when there was an actual memory leak, and when it's this moved pointer issue.


I could be wrong, but I don't think the code you just posted would be emitting a leak warning.
Please do the work of actually making a tiny test that's JUST the posted code and verify that Gmock complains about it.

What I see in the posted code HERE is correct, and there's no leak to complain about.

In your REAL code, do you have a unique_ptr at namespace scope or in a static class member?

 

--

---
You received this message because you are subscribed to the Google Groups "Google C++ Mocking Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.

Alex Shaver

unread,
Jan 14, 2015, 11:11:33 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
Yes the most recent code was copy pasted, but just in case, I condensed the entire test into one singular file and only

#include "gtest/gtest.h"

#include "gmock/gmock.h"

#include <memory>

class A{
public:
    virtual void Arc() = 0;
};

class Mock_A : public A{
public:
    Mock_A() = default;
    virtual ~Mock_A() = default;

    MOCK_METHOD0(Arc, void());
};

class Foo{
public:
    Foo(std::unique_ptr<A> alice) : Alice(std::move(alice)){}
    virtual ~Foo() = default;

    void DoStuff(){ Alice->Arc(); }

    std::unique_ptr<A> Alice;
};

TEST(Foo, DoStuff){
    std::unique_ptr<Mock_A> Alice(new Mock_A());
    EXPECT_CALL(*Alice, Arc());

    Foo foo(std::move(Alice));
    foo.DoStuff();
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

 which has output
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Foo
[ RUN ] Foo.DoStuff
[ OK ] Foo.DoStuff (0 ms)
[----------] 1 test from Foo (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[ PASSED ] 1 test.
/home/amshaver/UniquePtrTesting/Test/UniquePtrTesting_TEST/main.cpp:32: ERROR: this mock object (used in test Foo.DoStuff) should be deleted but never is. Its address is @0x25c7820.
ERROR: 1 leaked mock object found at program exit.

Alex Shaver

unread,
Jan 14, 2015, 11:15:25 AM1/14/15
to googl...@googlegroups.com, alexs...@gmail.com
Finally fixed. And yes, it was my fault all along. Again I do appreciate the help trying to Isolate the issue.

if I do not explicitly  include the base class's destructor, even just as a default, the test complains of a memory leak. 

class A{
public:
  A
() = default;
 
virtual ~A() = default;


 
virtual void Arc() = 0;
}


When I do indicate it, the test passes fine. 
...

Billy Donahue

unread,
Jan 14, 2015, 1:37:10 PM1/14/15
to Alex Shaver, googl...@googlegroups.com

Yes, a base class almost always needs a virtual destructor.
The unique_ptr<Base> deleter will call the ~Base destructor. If that's not virtual, the derived part of the object won't be destroyed.

This is a C++ gotcha.

It doesn't matter if it's 'default' or not. It just has to be marked virtual for this test to work.


--

---
You received this message because you are subscribed to the Google Groups "Google C++ Mocking Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to googlemock+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages