How can I reuse the same impl destructor in a class derived from a PIMPL base class?












1














I'm trying to create a class that inherits from a base class that uses the PIMPL idiom.



I have a base class base.h:



#include <memory>

class Base {
public:
class Impl;
Base(std::unique_ptr<Base::Impl> impl);
virtual ~Base();

private:
std::unique_ptr<Base::Impl> impl_;
};


which is implemented in base.cpp:



#include "base.h"

class Base::Impl {
public:
Impl() {}
~Impl() {}
};

Base::Base(std::unique_ptr<Base::Impl> impl) : impl_(std::move(impl)) {}
Base::~Base() {}


which is then derived in derived.cpp:



#include "base.h"

class Derived : public Base {
public:
Derived() : Base(nullptr) {}
~Derived() override {}
};


When I compile these three files, I get the following error:



In file included from /usr/include/c++/7/memory:80:0,
from base.h:1,
from derived.cpp:1:
/usr/include/c++/7/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Base::Impl]’:
/usr/include/c++/7/bits/unique_ptr.h:268:17: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Base::Impl; _Dp = std::default_delete<Base::Impl>]’
derived.cpp:5:27: required from here
/usr/include/c++/7/bits/unique_ptr.h:76:22: error: invalid application of ‘sizeof’ to incomplete type ‘Base::Impl’
static_assert(sizeof(_Tp)>0,


which kind of makes sense, since there is no ~Impl() for the derived class to use. After I add the following snippet to derived.cpp before the Derived class definition:



class Base::Impl {
public:
Impl() {}
~Impl() {}
};


it compiles fine. Is there any way for derived.cpp to use the Impl destructor from base.cpp without adding it to some other shared file that both base.cpp and derived.cpp use? I've also noticed that this issue only arises because of the constructor taking in a unique_ptr to Base::Impl. If I replace that constructor with an empty constructor that just assigns a new Impl to Base::impl_, I don't have to include the destructor like I had to above. What's different in that situation?










share|improve this question
























  • The problem is the conversion of nullptr into a std::unique_ptr<Base::Impl> happening outside of Base.cpp where Impl is fully defined. This leads to the reason why I'm not trying to answer this: I can't provide a good solution. If only Base knows how to make a Impl, how will Derived ever get an Impl to supply to Base? This constructor seems minimally useful. Or maybe I do have a solution.... Lemme think.
    – user4581301
    Nov 19 at 23:51










  • It does seem a bit strange, but for context, the Derived class in my use case is a mock, so I have no need to construct an Impl.
    – srujzs
    Nov 19 at 23:57










  • Advice would be don't then. Add another constructor to Base. Base::Base() : impl_(nullptr) {} That said, I hate hate hate modifying a class to support a test. It means you are not testing the proper use-cases of the system under test and the test results may be questionable.
    – user4581301
    Nov 20 at 0:08










  • Thinking didn't coalesces into a decent solution, by the way.
    – user4581301
    Nov 20 at 0:09
















1














I'm trying to create a class that inherits from a base class that uses the PIMPL idiom.



I have a base class base.h:



#include <memory>

class Base {
public:
class Impl;
Base(std::unique_ptr<Base::Impl> impl);
virtual ~Base();

private:
std::unique_ptr<Base::Impl> impl_;
};


which is implemented in base.cpp:



#include "base.h"

class Base::Impl {
public:
Impl() {}
~Impl() {}
};

Base::Base(std::unique_ptr<Base::Impl> impl) : impl_(std::move(impl)) {}
Base::~Base() {}


which is then derived in derived.cpp:



#include "base.h"

class Derived : public Base {
public:
Derived() : Base(nullptr) {}
~Derived() override {}
};


When I compile these three files, I get the following error:



In file included from /usr/include/c++/7/memory:80:0,
from base.h:1,
from derived.cpp:1:
/usr/include/c++/7/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Base::Impl]’:
/usr/include/c++/7/bits/unique_ptr.h:268:17: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Base::Impl; _Dp = std::default_delete<Base::Impl>]’
derived.cpp:5:27: required from here
/usr/include/c++/7/bits/unique_ptr.h:76:22: error: invalid application of ‘sizeof’ to incomplete type ‘Base::Impl’
static_assert(sizeof(_Tp)>0,


which kind of makes sense, since there is no ~Impl() for the derived class to use. After I add the following snippet to derived.cpp before the Derived class definition:



class Base::Impl {
public:
Impl() {}
~Impl() {}
};


it compiles fine. Is there any way for derived.cpp to use the Impl destructor from base.cpp without adding it to some other shared file that both base.cpp and derived.cpp use? I've also noticed that this issue only arises because of the constructor taking in a unique_ptr to Base::Impl. If I replace that constructor with an empty constructor that just assigns a new Impl to Base::impl_, I don't have to include the destructor like I had to above. What's different in that situation?










share|improve this question
























  • The problem is the conversion of nullptr into a std::unique_ptr<Base::Impl> happening outside of Base.cpp where Impl is fully defined. This leads to the reason why I'm not trying to answer this: I can't provide a good solution. If only Base knows how to make a Impl, how will Derived ever get an Impl to supply to Base? This constructor seems minimally useful. Or maybe I do have a solution.... Lemme think.
    – user4581301
    Nov 19 at 23:51










  • It does seem a bit strange, but for context, the Derived class in my use case is a mock, so I have no need to construct an Impl.
    – srujzs
    Nov 19 at 23:57










  • Advice would be don't then. Add another constructor to Base. Base::Base() : impl_(nullptr) {} That said, I hate hate hate modifying a class to support a test. It means you are not testing the proper use-cases of the system under test and the test results may be questionable.
    – user4581301
    Nov 20 at 0:08










  • Thinking didn't coalesces into a decent solution, by the way.
    – user4581301
    Nov 20 at 0:09














1












1








1


1





I'm trying to create a class that inherits from a base class that uses the PIMPL idiom.



I have a base class base.h:



#include <memory>

class Base {
public:
class Impl;
Base(std::unique_ptr<Base::Impl> impl);
virtual ~Base();

private:
std::unique_ptr<Base::Impl> impl_;
};


which is implemented in base.cpp:



#include "base.h"

class Base::Impl {
public:
Impl() {}
~Impl() {}
};

Base::Base(std::unique_ptr<Base::Impl> impl) : impl_(std::move(impl)) {}
Base::~Base() {}


which is then derived in derived.cpp:



#include "base.h"

class Derived : public Base {
public:
Derived() : Base(nullptr) {}
~Derived() override {}
};


When I compile these three files, I get the following error:



In file included from /usr/include/c++/7/memory:80:0,
from base.h:1,
from derived.cpp:1:
/usr/include/c++/7/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Base::Impl]’:
/usr/include/c++/7/bits/unique_ptr.h:268:17: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Base::Impl; _Dp = std::default_delete<Base::Impl>]’
derived.cpp:5:27: required from here
/usr/include/c++/7/bits/unique_ptr.h:76:22: error: invalid application of ‘sizeof’ to incomplete type ‘Base::Impl’
static_assert(sizeof(_Tp)>0,


which kind of makes sense, since there is no ~Impl() for the derived class to use. After I add the following snippet to derived.cpp before the Derived class definition:



class Base::Impl {
public:
Impl() {}
~Impl() {}
};


it compiles fine. Is there any way for derived.cpp to use the Impl destructor from base.cpp without adding it to some other shared file that both base.cpp and derived.cpp use? I've also noticed that this issue only arises because of the constructor taking in a unique_ptr to Base::Impl. If I replace that constructor with an empty constructor that just assigns a new Impl to Base::impl_, I don't have to include the destructor like I had to above. What's different in that situation?










share|improve this question















I'm trying to create a class that inherits from a base class that uses the PIMPL idiom.



I have a base class base.h:



#include <memory>

class Base {
public:
class Impl;
Base(std::unique_ptr<Base::Impl> impl);
virtual ~Base();

private:
std::unique_ptr<Base::Impl> impl_;
};


which is implemented in base.cpp:



#include "base.h"

class Base::Impl {
public:
Impl() {}
~Impl() {}
};

Base::Base(std::unique_ptr<Base::Impl> impl) : impl_(std::move(impl)) {}
Base::~Base() {}


which is then derived in derived.cpp:



#include "base.h"

class Derived : public Base {
public:
Derived() : Base(nullptr) {}
~Derived() override {}
};


When I compile these three files, I get the following error:



In file included from /usr/include/c++/7/memory:80:0,
from base.h:1,
from derived.cpp:1:
/usr/include/c++/7/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Base::Impl]’:
/usr/include/c++/7/bits/unique_ptr.h:268:17: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Base::Impl; _Dp = std::default_delete<Base::Impl>]’
derived.cpp:5:27: required from here
/usr/include/c++/7/bits/unique_ptr.h:76:22: error: invalid application of ‘sizeof’ to incomplete type ‘Base::Impl’
static_assert(sizeof(_Tp)>0,


which kind of makes sense, since there is no ~Impl() for the derived class to use. After I add the following snippet to derived.cpp before the Derived class definition:



class Base::Impl {
public:
Impl() {}
~Impl() {}
};


it compiles fine. Is there any way for derived.cpp to use the Impl destructor from base.cpp without adding it to some other shared file that both base.cpp and derived.cpp use? I've also noticed that this issue only arises because of the constructor taking in a unique_ptr to Base::Impl. If I replace that constructor with an empty constructor that just assigns a new Impl to Base::impl_, I don't have to include the destructor like I had to above. What's different in that situation?







c++ inheritance unique-ptr pimpl-idiom






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 19 at 23:39

























asked Nov 19 at 23:07









srujzs

647




647












  • The problem is the conversion of nullptr into a std::unique_ptr<Base::Impl> happening outside of Base.cpp where Impl is fully defined. This leads to the reason why I'm not trying to answer this: I can't provide a good solution. If only Base knows how to make a Impl, how will Derived ever get an Impl to supply to Base? This constructor seems minimally useful. Or maybe I do have a solution.... Lemme think.
    – user4581301
    Nov 19 at 23:51










  • It does seem a bit strange, but for context, the Derived class in my use case is a mock, so I have no need to construct an Impl.
    – srujzs
    Nov 19 at 23:57










  • Advice would be don't then. Add another constructor to Base. Base::Base() : impl_(nullptr) {} That said, I hate hate hate modifying a class to support a test. It means you are not testing the proper use-cases of the system under test and the test results may be questionable.
    – user4581301
    Nov 20 at 0:08










  • Thinking didn't coalesces into a decent solution, by the way.
    – user4581301
    Nov 20 at 0:09


















  • The problem is the conversion of nullptr into a std::unique_ptr<Base::Impl> happening outside of Base.cpp where Impl is fully defined. This leads to the reason why I'm not trying to answer this: I can't provide a good solution. If only Base knows how to make a Impl, how will Derived ever get an Impl to supply to Base? This constructor seems minimally useful. Or maybe I do have a solution.... Lemme think.
    – user4581301
    Nov 19 at 23:51










  • It does seem a bit strange, but for context, the Derived class in my use case is a mock, so I have no need to construct an Impl.
    – srujzs
    Nov 19 at 23:57










  • Advice would be don't then. Add another constructor to Base. Base::Base() : impl_(nullptr) {} That said, I hate hate hate modifying a class to support a test. It means you are not testing the proper use-cases of the system under test and the test results may be questionable.
    – user4581301
    Nov 20 at 0:08










  • Thinking didn't coalesces into a decent solution, by the way.
    – user4581301
    Nov 20 at 0:09
















The problem is the conversion of nullptr into a std::unique_ptr<Base::Impl> happening outside of Base.cpp where Impl is fully defined. This leads to the reason why I'm not trying to answer this: I can't provide a good solution. If only Base knows how to make a Impl, how will Derived ever get an Impl to supply to Base? This constructor seems minimally useful. Or maybe I do have a solution.... Lemme think.
– user4581301
Nov 19 at 23:51




The problem is the conversion of nullptr into a std::unique_ptr<Base::Impl> happening outside of Base.cpp where Impl is fully defined. This leads to the reason why I'm not trying to answer this: I can't provide a good solution. If only Base knows how to make a Impl, how will Derived ever get an Impl to supply to Base? This constructor seems minimally useful. Or maybe I do have a solution.... Lemme think.
– user4581301
Nov 19 at 23:51












It does seem a bit strange, but for context, the Derived class in my use case is a mock, so I have no need to construct an Impl.
– srujzs
Nov 19 at 23:57




It does seem a bit strange, but for context, the Derived class in my use case is a mock, so I have no need to construct an Impl.
– srujzs
Nov 19 at 23:57












Advice would be don't then. Add another constructor to Base. Base::Base() : impl_(nullptr) {} That said, I hate hate hate modifying a class to support a test. It means you are not testing the proper use-cases of the system under test and the test results may be questionable.
– user4581301
Nov 20 at 0:08




Advice would be don't then. Add another constructor to Base. Base::Base() : impl_(nullptr) {} That said, I hate hate hate modifying a class to support a test. It means you are not testing the proper use-cases of the system under test and the test results may be questionable.
– user4581301
Nov 20 at 0:08












Thinking didn't coalesces into a decent solution, by the way.
– user4581301
Nov 20 at 0:09




Thinking didn't coalesces into a decent solution, by the way.
– user4581301
Nov 20 at 0:09

















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383923%2fhow-can-i-reuse-the-same-impl-destructor-in-a-class-derived-from-a-pimpl-base-cl%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383923%2fhow-can-i-reuse-the-same-impl-destructor-in-a-class-derived-from-a-pimpl-base-cl%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

"Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

Alcedinidae

RAC Tourist Trophy